簡體   English   中英

為什么 python 請求默認不使用系統 ssl 證書?

[英]Why python requests not use the system ssl cert by default?

背景:

我正在研究Ubuntu 18.04.1 LTS ,使用 next 安裝自簽名證書:

$ cp -rf my.crt /usr/local/share/ca-certificates/
$ update-ca-certificates

一切正常,因為現在我可以使用 next 成功訪問我的 web:

$ curl https://example.com

問題:

但是,當我使用python3 requests訪問時,它報告了下一個錯誤:

>>> requests.get("https://example.com")
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py", line 382, in _make_request
    self._validate_conn(conn)
  File "/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py", line 1010, in _validate_conn
    conn.connect()
  File "/usr/local/lib/python3.6/dist-packages/urllib3/connection.py", line 421, in connect
    tls_in_tls=tls_in_tls,
  File "/usr/local/lib/python3.6/dist-packages/urllib3/util/ssl_.py", line 429, in ssl_wrap_socket
    sock, context, tls_in_tls, server_hostname=server_hostname
  File "/usr/local/lib/python3.6/dist-packages/urllib3/util/ssl_.py", line 472, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "/usr/lib/python3.6/ssl.py", line 817, in __init__
    self.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:847)

額外的:

但是,如果我明確指定 crt,它會成功運行:

>>> requests.get("https://example.com", verify='/etc/ssl/certs/ca-certificates.crt')
<Response [200]>

問題:

我使用的是第三方代碼,這意味着我無法更改 python 代碼。

所以,我的問題是:為什么 python 請求不默認在/etc/ssl/certs/ca-certificates.crt中查找verify 我認為這是 ubuntu 上的默認認證,因為curl默認成功找到此證書...

而且,如果可能的話,我可以在 python 代碼之外設置任何帶有export的變量,那么 python 請求將默認查找認證?

我找到了根本原因,實際上這些requests會調用where using from certifi import where to find the proper CA on this pc。

但是,在 ubuntu 中安裝certifi模塊有兩種方式:

選項1:

apt-get install -y python3-certifi

選項 2:

pip3 install certifi

注意:如果直接使用pip3 install requests ,如果沒有為python3-certifi安裝certifi package ,它將使用pip3隱式安裝證書。

但是,看起來 Canonical(Ubuntu 的支持者)對certifi進行了一些更改,因此如果使用python3-certifi from apt ,則def where is next 或類似的代碼因不同版本而異:

root@4e1aab76e082:/# cat /usr/lib/python3/dist-packages/certifi/core.py
def where():
    return "/etc/ssl/certs/ca-certificates.crt"

但是如果使用pip3安裝,會是:

root@4e1aab76e082:/# cat /usr/local/lib/python3.6/dist-packages/certifi/core.py
def where():
    _CACERT_CTX = get_path("certifi", "cacert.pem")

那是 package 中的/usr/local/lib/python3.6/dist-packages/certifi/cacert.pem

所以關於 ubuntu 的解決方法是:使用apt-get install python3-certifi安裝 ubuntu 變體certifi ,卸載 pip 一個。 然后,我們無法更改任何應用程序代碼。

更新:

我找到了另一種與官方證書一起使用的方法,使用下一個變量,我還可以讓python requests module go 從我指定的位置獲取 CA,而無需更改應用程序代碼:

export REQUESTS_CA_BUNDLE='/etc/ssl/certs/ca-certificates.crt'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM