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

标签 ruby api openssl certificate

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

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

环顾四周,我发现很多人都遇到了这个错误。通常它带有自签名证书,他们只是想让它消失,所以他们做了一些肮脏的事情,比如 XMLRPC::Client 打开它的 http session 的方式。

我首先假设这只是客户端不关心证书是否有效,所以我继续搜索并遇到了 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 库)不同意。我所有的网络浏览器都说证书很好。

一些可能有用的其他细节。证书是通配符,但对域有效。 openssl s_client 与 Ruby 代码在同一台机器上运行几秒钟。这是与 RVM 一起安装的 Ruby 1.8.7 p357。

Ruby 是否使用主机操作系统提供的 CA 包以外的其他东西?有没有办法告诉 Ruby 使用特定的 CA 包或系统包?

最佳答案

如果您只对如何使 Ruby 的行为与 OpenSSL 相同 s_client 感兴趣或者您的浏览器有问题,您可以跳到最后一部分,我将在接下来的内容中详细说明。

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

  • Store#add_file 采用 PEM/DER 编码证书的路径
  • Store#add_cert 采用 X509::Certificate
  • 的实例
  • Store#add_path 获取可以找到受信任证书的目录的路径

  • “浏览器”方法

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

    Ruby 方法

    另一方面,典型 Rub​​y 应用程序的需求与浏览器的需求大不相同。浏览器必须能够让您导航到任何带有 TLS 证书并通过 https 提供服务的“合法”网站。但在典型的 Ruby 应用程序中,您只需处理少数使用 TLS 或需要证书验证的服务。

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

    然而,正如您已经注意到的那样,这样做的缺点是,默认情况下,如果您不主动添加受信任的证书,OpenSSL 扩展将根本无法验证任何对等证书。为了使事情正常工作,您必须手动设置配置。

    这种不便导致了很多可疑的措施来规避它,最糟糕的是全局设置OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE .请不要这样做。我们甚至开玩笑说,如果我们遇到这种 hack,添加代码会让您的应用程序随机崩溃:)

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

    为什么s_client可以验证证书

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

    使 Ruby 表现得像 s_client

    如果您在使用 Ruby 验证证书时仍然希望获得同样的舒适度,您可以通过调用 OpenSSL::X509::Store#set_default_paths 告诉它使用 OpenSSL 可信证书包(如果您的系统在您的系统上可用)。 .更多信息可以在 here 中找到.与 XMLRPC::Client 一起使用,只需确保 set_default_pathsX509::Store 上被调用它用。

    关于ruby - 为什么 Ruby 无法验证 SSL 证书?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9199660/

    相关文章:

    ruby - 如何在 node.js 中执行此 PKCS7 签名?

    php - API系统的安全性| PHP 语言

    java - java vector 方法set()和setElementAt()有什么区别?

    c - SSL_CTX_use_certificate_file 因 EXC_BAD_ACCESS 而失败

    c - _fopen$UNIX2003 引用自 OpenSSL 问题

    html - 将自定义变量发送给部分 - 中间人

    ruby - 在 Ruby 中制作一个方形乘法表

    asp.net - 如何在powershell中执行具有[[FromForm]]参数的API PUT方法

    XCode 在/usr/include 中找不到 OpenSSL header

    ruby - 注入(inject)方法如何工作?