python-requests urllib3教學 - Python請求引發SSLError




content post (17)

我必須從Python 3.4.0升級到3.4.6

pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt

我正在研究一個涉及CAS,jspring安全檢查,重定向等的簡單腳本。我想使用Kenneth Reitz的python請求,因為它是一項偉大的工作! 但是,CAS需要通過SSL進行驗證,因此我必須先通過該步驟。 我不知道Python要求的是什麼? 這個SSL證書應該放在哪裡?

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
  response = requests.get(url1, headers=headers)
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
  File "build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request 
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

如果請求調用被隱藏在代碼的深處,並且您不想安裝服務器證書,那麼僅僅為了調試目的 ,可以對請求進行monkeypatch:

import requests.api
import warnings


def requestspatch(method, url, **kwargs):
    kwargs['verify'] = False
    return _origcall(method, url, **kwargs)

_origcall = requests.api.request
requests.api.request = requestspatch
warnings.warn('Pathched requests: SSL verification disabled!')

切勿在生產中使用!


我打了小時這個問題。

我試圖更新請求。 然後我更新了certifi。 我指出驗證certifi.where()(代碼默認這是默認情況下)。 沒有工作。

最後我把我的python版本更新到python 2.7.11。 我在Python 2.7.5上,它與證書的驗證方式有些不兼容。 一旦我更新了Python(以及其他一些依賴項),它就開始工作了。


經過幾個小時的調試後,我只能使用下列軟件包來實現這個功能:

requests[security]==2.7.0  # not 2.18.1
cryptography==1.9  # not 2.0

使用OpenSSL 1.0.2g 1 Mar 2016

如果沒有這些包, verify=False不起作用。

我希望這可以幫助別人。


我使用gspread面對同樣的問題,這些命令適用於我:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28

正如@Rafael Almeida所提到的,您遇到的問題是由不可信的SSL證書引起的。 在我的情況下,SSL證書不受我的服務器的信任。 為了在不影響安全性的情況下解決這個問題,我下載了證書並將其安裝到服務器上(只需雙擊.crt文件,然後安裝證書...)。


從請求有關SSL驗證的文檔

請求可以驗證HTTPS請求的SSL證書,就像Web瀏覽器一樣。 要檢查主機的SSL證書,可以使用verify參數:

>>> requests.get('https://kennethreitz.com', verify=True)

如果您不想驗證您的SSL證書,請將verify=False



我遇到同樣的問題和SSL證書驗證失敗的問題,當使用aws boto3,通過審查boto3代碼,我發現REQUESTS_CA_BUNDLE沒有設置,所以我通過手動設置它解決了這兩個問題:

from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

對於aws-cli,我想在~/.bashrc設置REQUESTS_CA_BUNDLE可以解決這個問題(未經測試,因為我的aws-cli沒有它)。

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

我遇到了同樣的問題。 原來我沒有在我的服務器上安裝中間證書(只需將它附加到證書的底部,如下所示)。

https://www.digicert.com/ssl-support/pem-ssl-creation.htm

確保你已經安裝了ca-certificates包:

sudo apt-get install ca-certificates

更新時間也可能解決這個問題:

sudo apt-get install ntpdate
sudo ntpdate -u ntp.ubuntu.com

如果您使用的是自簽名證書,則可能需要手動將其添加到系統中。


如果你不打擾證書,只需使用verify=False

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)

$ pip install -U requests[security]

  • 測試Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • 測試Python 2.7.5 @ MacOSX 10.9.5(小牛隊)

當此問題已打開(2012-05)時,請求版本為0.13.1。 在版本2.4.1(2014-09)中引入了“安全”附加功能,使用certifi包(如果可用)。

現在(2016-09)主版本是2.11.1, 沒有 verify=False ,效果很好。 無需使用requests.get(url, verify=False) ,如果安裝了requests[security]額外的。


如果你有一個依賴於requests的庫,並且你不能修改驗證路徑(就像使用pyvmomi ),那麼你必須找到與請求捆綁在一起的cacert.pem並在那裡附加你的CA. 以下是查找cacert.pem位置的一般方法:

視窗

C:\>python -c "import requests; print requests.certs.where()"
c:\Python27\lib\site-packages\requests-2.8.1-py2.7.egg\requests\cacert.pem

Linux的

#  (py2.7.5,requests 2.7.0, verify not enforced)
[email protected]:~/# python -c "import requests; print requests.certs.where()"
/usr/lib/python2.7/dist-packages/certifi/cacert.pem

#  (py2.7.10, verify enforced)
[email protected]:~/# python -c "import requests; print requests.certs.where()"
/usr/local/lib/python2.7/dist-packages/requests/cacert.pem

順便說一句。 @ requests-devs,將你自己的cacerts與請求綁定在一起真的很煩人......特別是你似乎並沒有首先使用系統ca store,而這在任何地方都沒有記錄。

更新

在使用庫並且無法控制ca-bundle位置的情況下,您還可以明確地將ca-bundle位置設置為您的主機範圍的ca-bundle:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"

您遇到的問題是由不可信的SSL證書引起的。

像之前評論中提到的@dirk一樣, 最快的解決方法是設置verify=False

requests.get('https://example.com', verify=False)

請注意,這將導致證書不被驗證。 這會讓您的應用程序面臨安全風險,例如中間人攻擊。

當然,應用判斷。 正如評論中所提到的,這對於快速/一次性應用程序/腳本來說可能是可以接受的, 但實際上不應該用於生產軟件

如果只是跳過證書檢查在您的特定上下文中不可接受,請考慮以下選項,最好的選擇是將verify參數設置為證書的.pem文件路徑的字符串(您應該通過某些某種安全的手段)。

因此,從版本2.0開始, verify參數接受下列值以及它們各自的語義:

  • True :使證書針對圖書館自己的可信證書頒發機構進行驗證(注意:您可以通過Certifi庫查看哪些根證書請求使用了從請求中提取的RC信任數據庫: Certifi - 人類信任數據庫 )。
  • False完全繞過證書驗證。
  • 請求用於驗證證書的CA_BUNDLE文件的路徑。

來源: 請求 - SSL證書驗證

還要看看同一鏈接上的cert參數。


我找到了解決類似問題的具體方法。 這個想法指向存儲在system的cacert文件,並被另一個基於ssl的應用程序使用。

在Debian中(我不確定在其他發行版中是否也是如此)證書文件(.pem)存儲在/etc/ssl/certs/因此,這是適用於我的代碼:

import requests
verify='/etc/ssl/certs/cacert.org.pem'
response = requests.get('https://lists.cacert.org', verify=verify)

為了猜測什麼是pem文件,我瀏覽到url並檢查哪個證書頒發機構(CA)生成了證書。

編輯:如果你不能編輯代碼(因為你正在運行第三個應用程序),你可以嘗試直接添加到/usr/local/lib/python2.7/dist-packages/requests/cacert.pem (例如復制它到文件的末尾)。


要使用的CA文件的名稱可以通過verify

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

如果您使用verify=True那麼requests將使用自己的CA集合,該集合可能沒有簽署服務器證書的CA.


要記住的一件重要事情是容器的__str__使用包含的對象' __repr__

>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"

Python傾向於明確可讀性tuple__str__調用調用包含的對象' __repr__ ,即對象的“形式”表示。 雖然正式表示比非正式表達更難閱讀,但它對於錯誤是明確的和更強大的。





python ssl python-requests urllib3