这是我第一次try 使用XMLRPC::Client库与远程API交互,我一直收到以下错误:

warning: peer certificate won't be verified in this SSL session

我四处搜索,发现很多人都犯了这个错误.通常是使用自签名证书,他们只是想让它消失,所以他们会像XMLRPC::Client打开http会话那样做一些肮脏的事情,比如monkey patch.

我首先假设这只是客户不关心证书是否有效,所以我继续搜索,发现了this gem个.它只是强制验证所有SSL证书,如果无法验证,则会抛出一个硬错误.这正是我想要的.我包含了它,再次运行了代码,现在我得到了:

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

当然证书坏了!但我仔细判断了openssl的内置s_客户端,以确保:

openssl s_client -connect sub.example.com:443

我得到了什么:

CONNECTED(00000003)
---
Certificate chain
<snip>
Verify return code: 0 (ok)

现在我们来回答我的问题.OpenSSL(命令行版本)表示证书是好的.OpenSSL(Ruby库)不同意.我所有的网络浏览器都说证书是好的.

一些可能有用的额外细节.证书是通配符,但对域有效.openssl s_客户端在与Ruby代码相隔几秒钟的同一台机器上运行.这是与RVM一起安装的Ruby 1.8.7 p357.

Ruby使用的不是主机OS提供的CA包吗?有没有办法告诉Ruby使用特定的CA包或系统包?

推荐答案

如果您只对如何使Ruby与OpenSSL s_client或您的浏览器具有相同的行为方式感兴趣,您可以跳到最后一节,我将在下面介绍详细内容.

默认情况下,用于建立连接的OpenSSL::X509::Store根本不使用任何可信证书.根据您对应用程序域的了解,您通常会向X509::Store实例提供与您的应用程序相关的可信证书.有几种 Select :

  • Store#add_文件采用PEM/DER编码证书的路径
  • Store#add_cert以X509::Certificate为例
  • Store#add_path获取一个指向可以找到可信证书的目录的路径

"浏览器"方法

这与浏览器、Java(cacerts)或具有自己的内部可信证书存储的Windows所采用的方法不同.在那里,软件预先配备了一组受信任的证书,软件供应商认为这些证书"良好".一般来说,这不是一个坏主意,但如果您实际查看这些集合,您很快就会注意到证书太多了.个人无法真正判断这些证书中的all个是否应该盲目信任.

Ruby方法

另一方面,典型Ruby应用程序的要求与浏览器的要求有很大不同.浏览器必须能够让您导航到任何带有TLS证书并通过https提供服务的"合法"网站.但是在一个典型的Ruby应用程序中,您只需要处理一些使用TLS的服务,或者需要证书验证的服务.

Ruby方法还有一个好处——尽管它需要更多的手工工作,但最终会得到一个手工定制的解决方案,它完全信任给定应用程序上下文中应该信任的证书.这很乏味,但这种方式的安全性要高得多,因为expose 的攻击面要少得多.以最近发生的事件为例:如果你从来没有在你的信任集中包含DigiNotar或任何其他受损的根目录,那么这种违规行为就不会影响你.

然而,正如您已经注意到的那样,这样做的缺点是,默认情况下,如果您不主动添加受信任的证书,OpenSSL扩展将根本无法验证any个对等证书.为了让事情顺利进行,您必须手动设置配置.

这种不便导致了许多可疑的措施来规避它,最糟糕的是全球设定OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE.请不要这样做.我们甚至Jest 说,如果遇到这种黑客行为,添加的代码会让你的应用程序随机崩溃:)

如果手动信任设置看起来太复杂,我现在将提供一个简单的替代方案,使OpenSSL扩展的行为与OpenSSL CLI命令(如s_client)完全相同.

为什么s_客户端可以验证证书

OpenSSL对浏览器和Windows使用类似的方法.典型的安装会在硬盘上的某个位置放置一组可信证书(大约/etc/ssl/certs/ca-bundle.crt个),这将作为默认的可信证书集.这就是s_client在需要验证同级证书时的表现,这就是你的实验成功的原因.

让Ruby表现得像s_客户机

如果您仍然想在使用Ruby验证证书时获得同样的舒适感,可以通过拨打OpenSSL::X509::Store#set_default_paths告诉它使用OpenSSL可信证书Bundle 包(如果在您的系统上可用).更多信息请参见here.要将其用于XMLRPC::Client,只需确保set_default_paths在其使用的X509::Store上被调用.

Ruby相关问答推荐

Ruby中链表大小调用的时间复杂度

安全导航运算符的使用是否应该在两种情况下进行单元测试(对象存在 + 对象无)?

碰撞检测测试中对象的 Nil 类

在 Ruby 中,rescue语句可以嵌套在哪些 struct 中

ri 和 rdoc 有什么区别

何时在 Ruby 方法中使用 `self.foo` 而不是 `foo`

由模块中定义的另一个覆盖方法

如何在 Ruby 的 RestClient gem 中设置超时?

ruby中字符的整数值?

在 Ruby 中覆盖 == 运算符

对具有相同键的 2 个哈希属性求和

Ruby 中的排序稳定吗?

覆盖子类中的 ruby​​ 常量,以便继承的方法使用新常量而不是旧常量?

理解 Ruby 中的私有方法

HAML 中 Javascript 中的 Ruby 方法

判断 Ruby 中是否存在 URL

为什么 __FILE__ 大写而 __dir__ 小写?

Eclipse 的首选 Ruby 插件?

如何创建一个 Gemfile?

Docker for Mac - mkmf.rb 找不到 ruby​​ 的头文件