如果您遇到與 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 包,作為一般瀏覽器更新的一部分。
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 的說明以解決問題,請跳轉到疑難排解部分。
網際網路上的安全連接使用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。
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 憑證問題或 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
gem install bundler
您可能可以使用 self-update 命令升级 RubyGems
gem update --system
如果该命令失败,您可以尝试下载最新的 RubyGems 并安装它,使用以下步骤。在此示例中,我们将下载并安装 RubyGems 2.7.6。如果您在阅读此时,最新版本的 RubyGems 已更改,您需要将任何地方看到的 2.7.6
更改为您已下载的 RubyGems 版本。
cd ~/Downloads
。在 Windows 上,它将是 cd C:\Users\%USERNAME%\Downloads
。gem install --local rubygems-update-2.7.6.gem
安装下载的 RubyGems 升级 gem。update_rubygems
。完成!运行 gem --version
以验证您是否使用了最新版本的 RubyGems。
如果您的系统时钟设置为过去或未来的时间,则您的计算机将无法与 RubyGems.org 建立安全连接。要解决此问题,您需要将系统时钟设置为当前时间。在 Linux 中,您可以通过运行 sudo ntpdate ntp.ubuntu.com
更新系统时钟。
以下是更新系统时钟的其他可能解决方案
如果您無法更新 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,按照上一步的說明操作。
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-build
或 rbenv install
安裝按照 rbenv 提供的更新和疑難排解 ruby-build 指南中概述的步驟進行操作。
macOS 10.13 High Sierra 自帶與 TLSv1.2 兼容的默認 Ruby。
要檢查當前的 macOS 版本,請轉到蘋果菜單並選擇“關於本機”。如果您看到的不是“macOS High Sierra”,則需要升級到最新的 macOS(否則按照這些步驟後面的下一組指示安裝 Homebrew 中的更新版本 Ruby)。
要升級到 High Sierra
注意:要使用 Homebrew 安裝更新版本的 Ruby,首先確保已安裝 Homebrew。如果沒有 brew
命令,請按照https://brew.sh 上的安裝說明進行操作,然後再回到這些步驟。
brew update
brew install ruby
brew upgrade ruby
以升級到最新版本。apt-get
安裝注意:要使用 apt
移除 Ruby,您需要檢查您安裝了哪些版本的 Ruby。 apt
安裝的是 Ruby v2.3.1。
若要卸載,請按照此處列出的指示進行操作。(這些指示適用於 Ubuntu 和 Debian。)
成功卸載 Ruby 後,重新安裝它,執行以下命令:
$ sudo apt-get install ruby
dnf
安裝注意:最新版本的 Fedora 使用 dnf
作為其套件管理器,但舊版本則使用 yum
。如果看到錯誤消息 dnf: command not found
,請將這些指示中的 dnf
替換為 yum
。
首先,執行以下命令卸載 Ruby:
$ dnf remove ruby
然後重新安裝(此命令將安裝 Ruby 2.3)
$ dnf install ruby
yum
安裝按照這些指示在 CentOS 上升級 Ruby。(它們還包括用於排除 OpenSSL 的指示。)
從控制面板中,找到“程序”中的 Ruby 安裝程序。點擊文件夾,然後再次點擊“卸載 Ruby”。重新安裝,從RubyInstaller下載 Ruby 和 Ruby DevKit。
重新運行自動SSL 檢查以驗證問題是否與 SSL 問題或 TLS 問題有關。如果您已經按照上述疑難排解步驟進行操作,但仍然遇到問題,請參閱下面的創建問題部分進行下一步操作。
如果以上任何指示都未解決問題,則下一步是打開一個問題。
(如果您的錯誤來自 gem install
,則在RubyGems 問題跟蹤器中創建一個問題。如果來自 bundle install
,則在Bundler 問題跟蹤器中創建一個問題。)
請包括
gem env
的輸出bundle env
的輸出ruby -ropenssl -e 'puts OpenSSL::OPENSSL_LIBRARY_VERSION'
的輸出如果您找到了此處未列出的解決方案,請提交 PR 將您的解決方案添加到此指南中!