公司網路環境中使用Python requests 庫SSL認證失敗

逻辑北海發表於2024-09-04

問題描述

使用python request庫訪問一個https url會報錯,提示自簽名錯誤。但是在瀏覽器中訪問這個url就沒問題,在私人電腦上也沒問題。

Sample code:

import requests
import certifi

print(certifi.where())
response = requests.get('https://chroma-onnx-models.s3.amazonaws.com/all-MiniLM-L6-v2/onnx.tar.gz', verify=certifi.where())

報錯如下:

......
requests.exceptions.SSLError: HTTPSConnectionPool(host='chroma-onnx-models.s3.amazonaws.com', port=443): Max retries exceeded with url: /all-MiniLM-L6-v2/onnx.tar.gz (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1006)')))

原因分析

Python requests 庫沒有使用系統自帶的證書管理器。這意味著它建立的證書鏈可能跟同一臺電腦上的瀏覽器不一樣。
Copilot說,可能是因為公司的代理伺服器檢查了HTTPS流量,並且生成了一個自簽名證書返回給 Python requests 客戶端。因為公司的根證書不在 Python 的證書庫中,所以代理伺服器的證書不能被認證。
在私人電腦上沒這個問題,應該是因為沒有代理在中間生成一個自簽名證書。
所以,解決方案是新增你公司的根證書到 Python 正在用的 PEM 檔案,目的似乎是使代理伺服器的證書可以被認證,不再是自簽名。這個根證書可以在你的瀏覽器中檢視。
可以嘗試pip install pip_system_certs,或者手動將公司的ROOT CA新增到...\Lib\site-packages\certifi\cacert.pem

擴充閱讀

公司的代理伺服器如何影響HTTPS流量?
(From copilot)

在公司網路中,代理伺服器可能會攔截和檢查 HTTPS 流量,這種行為通常被稱為“中間人攻擊”(Man-in-the-Middle Attack, MITM),但在企業環境中,這種技術被合法地用於監控和保護網路安全。以下是詳細解釋:

  1. 代理伺服器的工作原理
    代理伺服器充當客戶端(如你的計算機)和目標伺服器(如你訪問的網站)之間的中介。當你在公司網路中訪問 HTTPS 網站時,請求首先傳送到代理伺服器,然後代理伺服器再將請求轉發給目標伺服器。

  2. SSL/TLS 加密
    HTTPS 使用 SSL/TLS 協議來加密資料傳輸,確保資料在傳輸過程中不被竊取或篡改。正常情況下,客戶端和目標伺服器之間建立一個安全的加密通道。

  3. 代理伺服器的攔截和檢查
    為了檢查 HTTPS 流量,代理伺服器會在客戶端和目標伺服器之間插入自己。具體步驟如下:

代理伺服器生成自簽名證書:代理伺服器會為目標網站生成一個自簽名證書,並將其傳送給客戶端。
客戶端信任代理伺服器的證書:如果客戶端信任代理伺服器的證書(通常透過在客戶端裝置上預裝代理伺服器的根證書),客戶端會接受這個自簽名證書,並與代理伺服器建立加密連線。
代理伺服器與目標伺服器建立連線:代理伺服器再與目標伺服器建立一個獨立的加密連線。
4. 證書驗證失敗的原因
由於代理伺服器使用的是自簽名證書,而不是目標伺服器的真實證書,客戶端在驗證證書時可能會失敗,具體原因包括:

缺少信任:如果客戶端沒有預裝代理伺服器的根證書,客戶端會認為代理伺服器的證書不可信,從而導致 SSL 證書驗證失敗。
證書鏈不完整:代理伺服器生成的自簽名證書可能不包含完整的證書鏈,導致驗證失敗。
證書不匹配:客戶端期望的證書與代理伺服器提供的證書不匹配,導致驗證失敗。
解決方法
安裝代理伺服器的根證書:在客戶端裝置上安裝並信任代理伺服器的根證書。
配置代理設定:確保在使用 requests 庫時正確配置代理設定,並指定正確的證書路徑。

相關文章