Heroku Rails Net :: HTTP:OpenSSL :: SSL :: SSLError:SSL_connect返回= 1 errno = 0状态= SSLv3读取服务器证书B:证书validation失败

我有一个在Heroku服务器上运行的Rails应用程序,我在通过HTTPS使用Net :: HTTP与外部服务器通信时遇到问题。 每当我尝试通过HTTPS POST到外部专有API时,我收到的错误是:

 OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed 

我已经花了几个小时谷歌搜索我遇到的问题的答案,但无济于事。 这是我的环境:

  • Heroku Dyno运行Cedar 14(运行Cedar 10,升级到Cedar 14,看它是否会影响问题 – 没有快乐)
  • Rails 3.2.14rc2
  • Ruby 2.1.2

“修复”我尝试过:

  • 运行certified gem (实际上似乎有助于通过Omniauth和Google的API进行通信)
  • Monkey-patch从validation方法列表中删除SSLv2,SSLv3 。 当我在Heroku的服务器上的控制台中尝试这个时,它似乎对GET方法运行良好,但在尝试运行Net::HTTP::Post.new而不是Net::HTTP::Get.new时,似乎完全忽略调整Net::HTTP::Get.new
  • 手动覆盖证书文件位置 。 我已经指定它使用操作系统的权限文件(在Cedar-14堆栈上是最新的),但仍然没有骰子。
  • 我也试过手动指定在Net :: HTTP对象上使用ssl_version="TLSv1_2"没有运气(它甚至报告了相同的SSLv3相关错误)

当在开发中本地运行时,通信似乎工作得很好(我已经使用了这里建议的RVM覆盖方法 ),但是当我在Heroku服务器上尝试时,我运气不好。

更新:即使使用RVM更新,它似乎也无法在本地运行。

最后,但并非最不重要的,这是我正在运行的代码的抽象变体:

 uri = URI.parse("https://api.mysite.com/api/v1") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") request = Net::HTTP::Post.new(uri.path, {'Content-Type' =>'application/json'}) request_body = "{\"post_body\": \"data1\"}" response = http.request(request) 

任何人对我还应该关注什么有任何建议?

Heroku无法validation您的服务器证书是否由其识别的CA根有效签名。 这可能是因为:

  1. 您的证书未经CA或中级签署(即自签名)
  2. 您的证书由Heroku不知道的CA签署(不太可能)
  3. API服务器未提供正确的中间证书,以帮助Heroku将其连接到有效的CA根。 (可能)

从shell中尝试openssl s_client -showcerts -connect your-api-host.com:443 。 你应该看到类似的东西:

 depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root verify return:1 depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Certification Authority verify return:1 depth=1 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Domain Validation Secure Server CA verify return:1 depth=0 OU = Domain Control Validated, OU = PositiveSSL, CN = www.coffeepowered.net verify return:1 

您特别希望确保链中的所有证书都返回verify return: 1 。 如果这可以从你的shell工作,那么你的机器可能已经安装了你的Heroku实例没有的root证书。

如果不确切知道您的API服务器返回了哪些证书,很难明确地回答这个问题,但您可能需要提供中间证书捆绑以及SSL证书本身。 此中间证书包将由您的SSL证书签名者提供,并可通过SSLCertificateChainFile在Apache中提供,或通过将中间人与您的证书(根据此文档 )连接在nginx中提供。

如果您无法更改API服务器的配置,那么您的“手动覆盖证书文件位置”解决方案可能非常接近正确(与提供中间证书的服务器相同,除了客户端执行此操作),但您可能无法为API服务器的证书提供正确的证书链包。 确保为OpenSSL提供了正确的中间证书链,并且它应该可以正常工作。