分享 一则 Ruby 和 OpenSSL CA 证书的问题

lgn21st · 发布于 2015年3月26日 · 最后由 will7v 回复于 2015年7月20日 · 5136 次阅读
3

作为一个版本控,总是希望保持电脑中各种软件到最新版本。

最近通过 brew 升级 OpenSSL 和 ruby-build 到最新,尤其是 ruby-build 支持最新的 Ruby 2.2.1,新版 Ruby 中针对 Symobl GC 的改进很让人期待,升级步骤略暴力,采用自毁重装的方式:

rm -rf ~/.rbenv
rbenv install 2.2.1
rbenv global 2.2.1

升级后发现所有的 ssl 的请求,都会报告证书验证错误,具体错误信息如下:

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

暂时的解决方案,bypass 掉 SSL 的证书验证步骤,在 Rails 的 initalizers 中增加一个文件 bypass_ssl_verification.rb,只一行代码:

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

不过 bypass 证书验证步骤只是权宜之计,在本地开发倒是无所谓,生产环境下必须不能这么干!因为如果不验证证书的话,其实是留下了安全隐患。造成证书验证错误问题的原因可能有三种:

  1. 通过 brew 升级 OpenSSL 的过程中,证书文件出了问题,损坏或者未正确安装。
  2. 证书正常安装,但是路径不匹配。
  3. 安装包中附带的证书文件过期了。

首先检查证书不存在或者路径不对,brew 安装的 openssl 会把证书位置存放在这里:

/usr/local/etc/openssl/cert.pem

Ruby 运行环境中的 OpenSSL 的默认证书位置:

ruby -e "require 'openssl'; puts OpenSSL::X509::DEFAULT_CERT_FILE"

检查后发现 Ruby 运行环境中的结果跟 brew 安装的 OpenSSL 证书的位置完全对得上,且证书文件存在,说明不是证书丢失或者路径问题,最大的可能是证书过期了。

如果之前没有通过 brew 安装过 openssl 的话,ruby-build 会在编译 Ruby 的过程中自动下载并编译一份 openssl 到 ~/.rbenv 目录下,但是我亲测下来 ruby-build 自带的 openssl 也会产生同样的错误,所以最后还是决定保留 brew 安装的 openssl 版本,然后手动下载更新 ca root 证书的方式解决问题:

wget -c http://curl.haxx.se/ca/cacert.pem
mv cacert.pem /usr/local/etc/openssl/cert.pem 

检查了一下,在 cert.pem 的头部有证书生成时间,是2015年2月25日,还算蛮新的。

##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Wed Feb 25 04:12:04 2015
##
共收到 12 条回复
370

You saved my life 👍

3

#2楼 @luikore :plus1: 这是科学使用证书的方法。

17424

好贴怎么这样沉了。

10804

如果是使用RVM的,可以先用 rvm osx-ssl-certs status all 查看CA证书的状态,如果显示Old,就用 rvm osx-ssl-certs update all 升级CA证书 这个方法,简单便捷

10804

另外,有人遇到过 OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: sslv3 alert handshake failure 这个错误并解决了的吗?

2880

#6楼 @crayon 遇到并解决多次, 可能原因有: 网络不通, 本地或服务器证书没更新, 证书被劫持, 服务器太忙, 本地防火墙设置, 需要客户端证书, 操作系统bug, OpenSSL 安装不完整/链接错误, OpenSSL 的 Ruby 绑定安装不完整, rubygems 太老以致于 rubygems/ssl_certs 里的证书过期, 人品不好等等....

首先你得定位出是哪个 url 出的问题, 最笨的是人肉二分查找肯定能找出来. 然后 curl -I 地址 看看报错信息是什么, 如果 curl 没问题而 Ruby 有问题, 大致可以知道是 Ruby 的安装问题了.

如果不想解决问题, 只想盖住问题, 可以尝试换台 VPS 上的机器重做, 一般都会好...

3

#7楼 @luikore 😂 折腾 OpenSSL 好艰辛,不拆。

10804

#7楼 @luikore 感谢你详细的回复 ruby是用rvm安装的,rvm已更新到最新,1.9、2.0、2.1、2.2四个版本的ruby都安装来试了,都是报同样的错误 ca证书更到最新,openssl更到最新,问题依然 然后,我用python 2.7调用同一个API,正常 curl -I也正常 但是,试过好几个其他人的电脑,只要是ruby环境,就报同样的错误 同时,Android 5.0的设备也出现了不能访问API的情况

本地环境下,实在不知道如何解决了,只能将目光转向服务端 SSL证书是配置在负载均衡的,负载均衡设备比较老,openssl版本比较低,但又一时无法联系厂商去升级 同时,做了全站的CDN,这个问题的排查变得更加困难

今天,终于解决了这个问题! 原先负载均衡里,Cipher没指定,是default,根据Chrome浏览器查看的结果,基本是3DES_EDE_CBC和RC4_128这两种 今天,把这个Cipher设置成了AES256-SHA,问题就解决了!

5508

好文章,顶起来!

5508

又来问题了,

wget -c http://curl.haxx.se/ca/cacert.pem
mv cacert.pem /usr/local/etc/openssl/cert.pem 

下载证书,更新之后,一切都正常了, 但是每天都会被替换掉,格式跟 ‘security find-certificate’ 生产出来的一样, 开头就是SHA1, 不包含,

##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Wed Feb 25 04:12:04 2015
##

然后Rails就又报错了! Any Idea?

15470

微信刚接的项目就掉这个坑,是看这个链接里sheharyarn的答案解决的 简单说就是下一个cacert.pem,把这个添加到zshrc环境变量里,每次都用这个证书做ssl验证

2 huacnlee 关闭了讨论 8月24日 15:03
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册