为什么Ruby无法验证SSL证书?

a6b3iqyw  于 2023-02-03  发布在  Ruby
关注(0)|答案(3)|浏览(215)

这是我第一次尝试使用XMLRPC::Client库与远程API交互,但我一直收到此错误:

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

我四处搜索,发现很多人都遇到过这个错误。通常是自签名证书,他们只是想让它消失,所以他们做了一些肮脏的事情,比如猴子补丁XMLRPC::Client打开它的http会话的方式。
我一开始以为这只是客户端不关心证书是否有效,所以我继续搜索,发现了this gem。它只是强制验证所有SSL证书,如果无法验证,则抛出一个硬错误。这正是我想要的。我包含了它,再次运行代码,现在我得到了以下结果:

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

当然!证书是坏的!但是我仔细检查了一下,以确保使用openssl的内置s_client,如下所示:

openssl s_client -connect sub.example.com:443

我得到了什么

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

所以现在我们来回答我的问题。OpenSSL(命令行版本)说证书是好的。OpenSSL(Ruby库)不同意。我所有的Web浏览器都说证书是好的。
一些可能有用的附加细节。证书是通配符,但对域有效。openssl s_client在Ruby代码之外的几秒钟内在同一台机器上运行。这是Ruby 1.8.7 p357,它是随RVM安装的。
Ruby是否使用了主机操作系统提供的CA包之外的东西?是否有方法告诉Ruby使用特定的CA包或系统的CA包?

ql3eal8s

ql3eal8s1#

如果您只对如何使Ruby的行为与OpenSSL s_client或您的浏览器相同感兴趣,您可以跳到最后一节,我将在下面介绍细节。
默认情况下,用于建立连接的OpenSSL::X509::Store根本不使用任何受信任证书。根据您对应用程序域的了解,您通常会为X509::Store示例提供与您的应用程序相关的受信任证书。为此,有以下几个选项:

  • 存储#add_file采用PEM/DER编码证书的路径
  • 存储#add_cert采用X509::证书的示例
  • Store#add_path采用可找到受信任证书的目录的路径

“浏览器”方法

这与浏览器、Java(cacerts),或者Windows有自己的内部存储的可信证书,take.在那里,软件预先配备了一组可信证书,在软件供应商看来,这些证书被认为是“好的”.一般来说,这是一个不错的主意,但如果你实际上查看这些集合,那么你很快就会注意到证书太多了,一个人无法真正判断是否应该盲目地信任所有这些证书。

Ruby方法

另一方面,典型的Ruby应用程序的要求与浏览器的要求有很大的不同。浏览器必须能够让您导航到任何带有TLS证书并通过https提供服务的“合法”网站。但在典型的Ruby应用程序中,您只需处理少数使用TLS或需要证书验证的服务。
Ruby方法还有一个好处--尽管它需要更多的手工工作,但最终您将得到一个手工定制的解决方案,该解决方案完全信任在给定应用程序上下文中它应该信任的证书。这很乏味,但这种方法的安全性要高得多,因为暴露的攻击面要少得多。以最近的事件为例:如果您从未将DigiNotar或任何其他受危害的根包含在您的信任集中,则此类违规行为不会影响您。
但是,正如您已经注意到的,这样做的缺点是,默认情况下,如果您不主动添加可信证书,OpenSSL扩展将无法验证 * 任何 * 对等证书。为了使其正常工作,您必须手动设置配置。
这种不便导致了许多可疑的措施来绕过它,最糟糕的是全局设置OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE。请不要这样做。我们甚至开玩笑说,如果我们遇到这种黑客攻击,可以添加代码让您的应用程序随机崩溃:)
如果手动信任设置看起来太复杂,我现在将提供一个简单的替代方案,使OpenSSL扩展的行为与s_client等OpenSSL CLI命令完全相同。

为什么s_client可以验证证书

OpenSSL使用类似于浏览器和Windows的方法。典型的安装会将一组可信证书放在硬盘上的某个地方(类似于/etc/ssl/certs/ca-bundle.crt),这将作为默认的可信证书集。s_client需要验证对等证书时会查找该位置,这也是您的实验成功的原因。

让Ruby像s_client一样运行

如果您仍然希望在使用Ruby验证证书时获得相同的舒适度,您可以通过调用OpenSSL::X509::Store#set_default_paths来告诉它使用OpenSSL受信任证书包(如果系统上有)。更多信息可以在此处找到。要在XMLRPC::Client中使用此功能,只需确保set_default_paths在其使用的X509::Store上被调用。

txu3uszq

txu3uszq2#

多亏了emboss的回答帮助我解决了这个问题。下面是我的解决方案,monkeypatch可以全局启用系统信任证书,而无需更改客户端代码。它适用于依赖net/http的gem。例如rest-client

module SetDefaultOpenSSLTrustStore
  def initialize(*args, **kwargs)
    super

    cert_store = OpenSSL::X509::Store.new
    cert_store.set_default_paths
    @cert_store = cert_store
  end
end

Net::HTTP.prepend SetDefaultOpenSSLTrustStore
jaql4c8m

jaql4c8m3#

如果您有ca-certificates文件,只需执行以下操作:

http.ca_file = <YOUR CA-CERT FILE PATH>
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5

相关问题