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根有效签名。 这可能是因为:
- 您的证书未经CA或中级签署(即自签名)
- 您的证书由Heroku不知道的CA签署(不太可能)
- 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提供了正确的中间证书链,并且它应该可以正常工作。