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

我在谷歌上搜索了好几个小时来寻找我遇到的问题的答案,但无济于事。这是我的环境:

"Fixes" 我试过了:

当 运行 在本地进行开发时(我使用 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 根有效签名。这可能是因为:

  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

您特别希望确保链中的所有证书 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 提供了正确的中间证书链,它应该可以正常工作。