Heroku Rails Net::HTTP: OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
Heroku Rails Net::HTTP: OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
我在 Heroku 服务器上有一个 Rails 应用程序 运行ning,我在使用 Net::HTTP 通过 HTTPS 与外部服务器通信时遇到问题。每当我尝试通过 HTTPS POST
到外部专有 API 时收到的错误是:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
我在谷歌上搜索了好几个小时来寻找我遇到的问题的答案,但无济于事。这是我的环境:
- Heroku Dyno 运行ning Cedar 14(之前是 运行ning Cedar 10,升级到 Cedar 14 看看它是否会影响这个问题 - 不高兴)
- Rails 3.2.14rc2
- Ruby 2.1.2
"Fixes" 我试过了:
- Running the
certified
gem(这实际上似乎有助于通过 Omniauth 和 Google 的 API 进行通信)
- Monkey-patch removing SSLv2, SSLv3 from the list of verification methods。当我在 Heroku 服务器的控制台中尝试此操作时,它似乎对 GET 方法运行良好,但在尝试 运行
Net::HTTP::Post.new
而不是 Net::HTTP::Get.new
[=47 时似乎完全忽略了调整=]
- Manually overriding the certificate file location。我已经指定它使用操作系统的权限文件(在 Cedar-14 堆栈上是最新的),但仍然没有骰子。
- 我也尝试在 Net::HTTP 对象上手动指定以使用
ssl_version="TLSv1_2"
但没有成功(它甚至一直报告相同的 SSLv3 相关错误)
当 运行 在本地进行开发时(我使用 RVM override method suggested here),通信似乎工作正常,但是当我在 Heroku 服务器上尝试时,我出局了运气。
更新: 看来即使更新了 RVM,这也无法在本地工作。
最后但同样重要的是,这是我 运行ning:
代码的抽象变体
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 无法验证您的服务器证书是否由它识别的 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
您特别希望确保链中的所有证书 return verify return: 1
。如果这适用于您的 shell,那么您的机器可能安装了您的 Heroku 实例没有的根证书。
在不知道您的 API 服务器正在 return 的确切证书的情况下,很难明确回答这个问题,但是您可能 需要服务于中间证书捆绑包以及 SSL 证书本身。这个中间证书包将由您的 SSL 证书签署者提供,并且可以通过 SSLCertificateChainFile, or in nginx by concatening the intermediates with your cert (per this documentation).
在 Apache 中提供。
如果您不能更改 API 服务器的配置,那么您的 "Manually overriding the certificate file location" 解决方案可能 非常 接近正确(相同就像服务器提供中间证书一样,客户端除外),但您可能没有为 API 服务器的证书提供正确的证书链包。确保您向 OpenSSL 提供了正确的中间证书链,它应该可以正常工作。
我在 Heroku 服务器上有一个 Rails 应用程序 运行ning,我在使用 Net::HTTP 通过 HTTPS 与外部服务器通信时遇到问题。每当我尝试通过 HTTPS POST
到外部专有 API 时收到的错误是:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
我在谷歌上搜索了好几个小时来寻找我遇到的问题的答案,但无济于事。这是我的环境:
- Heroku Dyno 运行ning Cedar 14(之前是 运行ning Cedar 10,升级到 Cedar 14 看看它是否会影响这个问题 - 不高兴)
- Rails 3.2.14rc2
- Ruby 2.1.2
"Fixes" 我试过了:
- Running the
certified
gem(这实际上似乎有助于通过 Omniauth 和 Google 的 API 进行通信) - Monkey-patch removing SSLv2, SSLv3 from the list of verification methods。当我在 Heroku 服务器的控制台中尝试此操作时,它似乎对 GET 方法运行良好,但在尝试 运行
Net::HTTP::Post.new
而不是Net::HTTP::Get.new
[=47 时似乎完全忽略了调整=] - Manually overriding the certificate file location。我已经指定它使用操作系统的权限文件(在 Cedar-14 堆栈上是最新的),但仍然没有骰子。
- 我也尝试在 Net::HTTP 对象上手动指定以使用
ssl_version="TLSv1_2"
但没有成功(它甚至一直报告相同的 SSLv3 相关错误)
当 运行 在本地进行开发时(我使用 RVM override method suggested here),通信似乎工作正常,但是当我在 Heroku 服务器上尝试时,我出局了运气。
更新: 看来即使更新了 RVM,这也无法在本地工作。
最后但同样重要的是,这是我 运行ning:
代码的抽象变体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 无法验证您的服务器证书是否由它识别的 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
您特别希望确保链中的所有证书 return verify return: 1
。如果这适用于您的 shell,那么您的机器可能安装了您的 Heroku 实例没有的根证书。
在不知道您的 API 服务器正在 return 的确切证书的情况下,很难明确回答这个问题,但是您可能 需要服务于中间证书捆绑包以及 SSL 证书本身。这个中间证书包将由您的 SSL 证书签署者提供,并且可以通过 SSLCertificateChainFile, or in nginx by concatening the intermediates with your cert (per this documentation).
在 Apache 中提供。如果您不能更改 API 服务器的配置,那么您的 "Manually overriding the certificate file location" 解决方案可能 非常 接近正确(相同就像服务器提供中间证书一样,客户端除外),但您可能没有为 API 服务器的证书提供正确的证书链包。确保您向 OpenSSL 提供了正确的中间证书链,它应该可以正常工作。