Docs header transparent bg

如何解決 RubyGems 和 Bundler 的 TLS/SSL 問題

如果您遇到與 SSL 憑證和/或 TLS 版本相關的問題,您來对了地方。在本指南中,我們將解釋這些問題是如何產生的以及如何解決它們。本指南中的許多說明都可以幫助解決 SSL 憑證問題或 TLS 版本問題。

如果您對原因不感興趣,只想盡快解決問題,您可以直接跳轉到解決 SSL 問題

目錄

問題

為什麼我看到 certificate verify failed

如果您在嘗試從 RubyGems 拉取更新時看到以下 SSL 錯誤:OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

當您的計算機缺少一個文件以驗證 RubyGems.org 背後的服務器是否正確時,會發生此錯誤。

RubyGems 的最新版本應該會解決此問題,因此我們建議更新到當前版本。要告訴 RubyGems 更新到最新版本,運行 gem update --system。如果這樣做不起作用,請嘗試下面的手動更新過程。

(我們所謂的更新 “應該解決此問題” 是什麼意思?請查看下面的這些證書是什麼?Ruby 如何使用 CA 證書 部分,以更好地了解潛在問題。)

這些證書是什麼?

每當您的計算機使用 HTTPS 與服務器通信時,它都會使用一個 SSL 憑證 作為該連接的一部分。該證書使您的計算機知道它正在與某個域的真實服務器通信,並使其確保您的計算機和該服務器可以完全私密地通信,而不讓其他計算機知道來回傳送的內容。

要確定 RubyGems.org 的證書是否正確,您的計算機會諮詢來自證書授權機構(CA)的另一個證書。CA 證書包括來自每家提供服務器 SSL 憑證的公司的證書,如 Verisign、Globalsign 等許多其他

每個 CA 都有一個「根」證書,用於驗證其他證書。CA 證書被稱為「根」,是因為它們簽署其他簽署其他證書的證書,而證書的圖表看起來像一棵樹,以「根」證書位於樹根的地方。您的電腦將使用內建的 CA 包含許多根證書,以確定是否信任特定網站提供的 SSL 證書,例如 RubyGems.org。

偶爾會有新公司添加到 CA 包中,或現有公司的證書到期並需要發放新的證書。對於大多數網站來說,這不是一個很大的問題,因為網頁瀏覽器定期更新其 CA 包,作為一般瀏覽器更新的一部分。

Ruby 如何使用 CA 證書

RubyGems.org 使用的 SSL 證書是從一個相對較新的根證書衍生出來的。Ruby(因此 RubyGems 和 Bundler)在與網站聯繫時並沒有定期更新的 CA 包可用。通常,Ruby 使用由操作系統(OS)提供的 CA 包。在較舊的操作系統上,這個 CA 包可能非常舊 - 即十年前的版本。由於這麼老的 CA 包無法驗證 RubyGems.org 的(相對較新的)證書,因此您可能會看到所討論的錯誤:certificate verify failed

進一步複雜化的是,18-24 個月前的一個與其他無關的變更導致 RubyGems.org 發放了一個新的 SSL 證書。這意味著需要驗證連接的「根」證書已更改。因此,即使您之前升級了 RubyGems/Bundler 以解決 SSL 問題,您仍然需要再次升級 - 這次是升級到更新的版本,擁有更新的證書。

解決憑證錯誤

首先,通過運行自動 SSL 檢查,並按照說明進行操作。您可能需要更新 Bundler更新 RubyGems手動更新 RubyGems 證書,或者甚至安裝新的 OS 證書

為什麼我看到 read server hello A

這個錯誤意味著您的機器無法與 RubyGems.org 建立安全連線。導致此問題的最常見原因是使用舊版 OpenSSL 的 Ruby。從 2018 年 1 月 1 日開始,連接到 RubyGems.org 需要 OpenSSL 1.0.1 或更新版本。

要了解為什麼需要那個版本,請繼續閱讀。要查看更新 OpenSSL 和/或 Ruby 的說明以解決問題,請跳轉到疑難排解部分

SSL 和 TLS 協議版本

網際網路上的安全連接使用HTTPS,這是 HTTP 的安全版本。最初,這種安全性是由 SSL(安全套接層)提供的。隨著時間的推移,研究人員發現了 SSL 中的缺陷,網路開發人員做出了變更和修復。在 SSL 3.0 之後,SSL 被 TLS 取代,或者稱為傳輸層安全性

隨著時間的推移,TLS 也進行了修訂。TLS 1.2 版本最初於 2011 年定義,並且從 2012 年起由 OpenSSL 支援,是目前的標準。在 2017 年,所有舊於 TLS 1.2 的 SSL 和 TLS 版本都被發現存在關鍵缺陷,可能被決心或具有相關知識的對手利用。因此,安全最佳實踐建議積極阻止所有 SSL 版本,以及 TLS 版本 1.0 和 1.1。

TLS 1.0 和 1.1 已被棄用

RubyGems.org 使用名為Fastly的第三方 CDN 提供程序,該提供程序使全球用戶能夠快速下載 gem。

去年,Fastly 宣布將停用 TLS 1.0 和 1.1 版本,原因是由 PCI 安全標準委員會發布的一項規定。(在 Fastly 的博客文章中了解更多

因此,從 2018 年 1 月開始,RubyGems.org 至少需要 TLSv1.2。這意味著 RubyGems.org 和 gem 命令將不再支持不支持 TLS 1.2 的 Ruby 和 OpenSSL 版本。

解決協議錯誤

要疑難排解協定連接錯誤,首先請運行自動 SSL 檢查,並按照說明進行操作。您可能需要更新 Bundler更新 RubyGems,甚至重新安裝 Ruby(您可以在版本管理器套件管理器中找到重新安裝說明)。

解決方案

自動 SSL 檢查

首先,運行此腳本來檢查您的錯誤是否是由 SSL 憑證問題或 TLS 版本問題造成的。

您可以使用以下命令立即運行腳本(Windows 10 也適用)

$ curl -Lks 'https://git.io/rg-ssl' | ruby

如果輸出為“由於缺少證書,您的 Ruby 無法連接到 rubygems.org”,則表示您存在證書驗證錯誤,需要更新您的證書。

如果您看到“您的 Ruby 无法连接到 rubygems.org,因为您的 OpenSSL 版本太旧”,则说明您的 OpenSSL 版本过旧,不兼容 TLSv1.2,您需要升级您的 OpenSSL 和/或重新编译 Ruby 以使用较新版本的 SSL。

本指南中的说明可以帮助您解决这两个问题。

更新 Bundler

通过运行以下命令更新到最新版本的 Bundler

gem install bundler

更新 RubyGems

您可能可以使用 self-update 命令升级 RubyGems

gem update --system

如果该命令失败,您可以尝试下载最新的 RubyGems 并安装它,使用以下步骤。在此示例中,我们将下载并安装 RubyGems 2.7.6。如果您在阅读此时,最新版本的 RubyGems 已更改,您需要将任何地方看到的 2.7.6 更改为您已下载的 RubyGems 版本。

  1. 使用您的网络浏览器,前往下载 RubyGems页面,并下载最新版本的 rubygems 的 gem 版本。
  2. 下载 gem 后,在 macOS 上打开 Terminal.app,在 Windows 上使用 Ruby 打开命令提示符。
  3. 将目录更改为您的 Downloads 文件夹。在 macOS 上,命令是 cd ~/Downloads。在 Windows 上,它将是 cd C:\Users\%USERNAME%\Downloads
  4. 通过运行 gem install --local rubygems-update-2.7.6.gem 安装下载的 RubyGems 升级 gem。
  5. 运行升级命令 update_rubygems

完成!运行 gem --version 以验证您是否使用了最新版本的 RubyGems。

更新系統時鐘

如果您的系统时钟设置为过去或未来的时间,则您的计算机将无法与 RubyGems.org 建立安全连接。要解决此问题,您需要将系统时钟设置为当前时间。在 Linux 中,您可以通过运行 sudo ntpdate ntp.ubuntu.com 更新系统时钟。

以下是更新系统时钟的其他可能解决方案

更新 CA 證書

安裝新的 RubyGems 證書

如果您無法更新 RubyGems,您可以手動添加 RubyGems 需要的憑證。如果您的 RubyGems 版本足夠新(2.1.x 及以上版本),可以使用這些“存放在本地”的憑證,並且成功安裝了憑證,則無需升級 RubyGems 版本即可正常工作。

警告:這些說明只會添加新的憑證;Ruby 將保持不變。為確保您的 Ruby 版本可以使用 TLSv1.2,請再次執行程式片段。如果不行,請按照本指南中另一組升級 Ruby 的說明進行操作。

步驟 1:取得新的信任憑證

從此連結下載 .pem 檔案:GlobalSignRootCA.pem

然後,找到下載的檔案,並檢查確保檔名以 .pem 結尾。(注意:某些瀏覽器會將副檔名更改為 .txt,這將導致無法正常工作。因此,重要的是確保下載的檔案以 .pem 副檔名結尾。)

步驟 2:找到您安裝的 RubyGems 憑證目錄

接下來,您需要找到安裝 Ruby 的目錄,以便在其中添加 .pem 檔案。

在 Windows:

打開命令行並輸入以下命令

C:\>gem which rubygems

您將看到如下輸出

C:/Ruby21/lib/ruby/2.1.0/rubygems.rb

要打開顯示所需目錄的視窗,請在同一窗口中輸入路徑部分直到檔案擴展名(但使用反斜線),例如,基於上面的輸出,您將運行此命令

C:\>start C:\Ruby21\lib\ruby\2.1.0\rubygems

這將打開一個探索器窗口,顯示安裝了 RubyGems 的目錄。

在 macOS:

打開終端並運行以下命令

$ gem which rubygems

您將看到如下輸出

/opt/rubies/2.4.1/lib/ruby/2.4.0/rubygems.rb

要打開顯示所需目錄的視窗,請將該輸出使用 open 命令,但不包括末尾的“.rb”,像這樣

$ open /opt/rubies/2.4.1/lib/ruby/2.4.0/rubygems

一個 Finder 窗口將打開,顯示安裝了 RubyGems 的目錄。

步驟 3:複製新的信任證書

在視窗中,打開 ssl_certs 目錄。找到其他像 AddTrustExternalCARoot.pem.pem 檔案(可能位於像 rubygems.org 這樣的子目錄中),並將您的檔案拖曳到它們的旁邊。

完成這些步驟後,您應該可以按照頂部的指示自動更新 RubyGems。進入更新 RubyGems章節,按步驟操作。如果這不起作用,請繼續按照本指南操作。

安裝新的操作系統證書

當 Homebrew 安裝的 OpenSSL 版本干擾 Ruby 找到正確證書時,此解決方案可能有效。有時,從頭開始卸載所有東西並重新開始就足以修復問題。

首先,您需要刪除 RVM。您可以運行以下命令來執行此操作

$ rvm implode

接下來,您需要從 Homebrew 中刪除 OpenSSL。(使用 --force 確保您刪除可能擁有的所有 OpenSSL 版本)

$ brew uninstall openssl --force

現在,您可以重新安裝 RVM,按照上一步的說明操作。

從版本管理器重新安裝 Ruby

使用 rvm 安裝

注意:如果使用 RVM 更新 SSL 證書不起作用,請嘗試此解決方案。如果即使更新了 RVM 安裝的 Ruby 仍然找不到正確的證書,您可以通過重新安裝 RVM 然後重新安裝 Ruby 版本來修復它。

運行以下命令來刪除 RVM 並重新安裝它

$ rvm implode $ \curl -sSL https://get.rvm.io | bash -s stable

然後,在重新安裝 Ruby 時告訴 RVM 您不想使用預編譯的二進位文件。(不幸的是,這將需要更長的時間,但希望這樣可以解決 SSL 問題。)

此命令將安裝 Ruby 2.2.3。請根據您需要安裝的 Ruby 版本調整命令

$ rvm install 2.2.3 --disable-binary

使用 ruby-buildrbenv install 安裝

按照 rbenv 提供的更新和疑難排解 ruby-build 指南中概述的步驟進行操作。

從操作系統套件管理器重新安裝 Ruby

macOS:內置 Ruby

macOS 10.13 High Sierra 自帶與 TLSv1.2 兼容的默認 Ruby。

要檢查當前的 macOS 版本,請轉到蘋果菜單並選擇“關於本機”。如果您看到的不是“macOS High Sierra”,則需要升級到最新的 macOS(否則按照這些步驟後面的下一組指示安裝 Homebrew 中的更新版本 Ruby)。

要升級到 High Sierra

    1. 打開 App Store 應用程序
    1. 選擇“更新”選項卡
    1. 單擊“安裝”按鈕下的“macOS High Sierra”

macOS:使用 Homebrew 安裝

注意:要使用 Homebrew 安裝更新版本的 Ruby,首先確保已安裝 Homebrew。如果沒有 brew 命令,請按照https://brew.sh 上的安裝說明進行操作,然後再回到這些步驟。

    1. 運行 brew update
    1. 運行 brew install ruby
    1. 如果 Ruby 已經安裝,運行 brew upgrade ruby 以升級到最新版本。

Debian 或 Ubuntu 16.04:使用 apt-get 安裝

注意:要使用 apt 移除 Ruby,您需要檢查您安裝了哪些版本的 Ruby。 apt 安裝的是 Ruby v2.3.1。

若要卸載,請按照此處列出的指示進行操作。(這些指示適用於 Ubuntu 和 Debian。)

成功卸載 Ruby 後,重新安裝它,執行以下命令:

$ sudo apt-get install ruby

Fedora:使用 dnf 安裝

注意:最新版本的 Fedora 使用 dnf 作為其套件管理器,但舊版本則使用 yum。如果看到錯誤消息 dnf: command not found,請將這些指示中的 dnf 替換為 yum

首先,執行以下命令卸載 Ruby:

$ dnf remove ruby

然後重新安裝(此命令將安裝 Ruby 2.3)

$ dnf install ruby

RHEL 或 CentOS:使用 yum 安裝

按照這些指示在 CentOS 上升級 Ruby。(它們還包括用於排除 OpenSSL 的指示。)

Windows:使用 Ruby Installer 安裝

從控制面板中,找到“程序”中的 Ruby 安裝程序。點擊文件夾,然後再次點擊“卸載 Ruby”。重新安裝,從RubyInstaller下載 Ruby 和 Ruby DevKit。

其他幫助

運行另一個自動 SSL 檢查

重新運行自動SSL 檢查以驗證問題是否與 SSL 問題或 TLS 問題有關。如果您已經按照上述疑難排解步驟進行操作,但仍然遇到問題,請參閱下面的創建問題部分進行下一步操作。

創建問題

如果以上任何指示都未解決問題,則下一步是打開一個問題。

(如果您的錯誤來自 gem install,則在RubyGems 問題跟蹤器中創建一個問題。如果來自 bundle install,則在Bundler 問題跟蹤器中創建一個問題。)

請包括

  • 運行 gem env 的輸出
  • 運行 bundle env 的輸出
  • 運行 ruby -ropenssl -e 'puts OpenSSL::OPENSSL_LIBRARY_VERSION' 的輸出
  • 您的 Ruby 版本管理器(如果有)
  • 您的操作系統和操作系統版本
  • 您的套件管理器名稱和版本(如果適用)

貢獻此指南

如果您找到了此處未列出的解決方案,請提交 PR 將您的解決方案添加到此指南中!

在 GitHub 上編輯此文件 如果您發現錯誤或發現遺漏了什麼。