1. 程式人生 > >七牛python sdk 上傳報SSL: CERTIFICATE_VERIFY_FAILED]

七牛python sdk 上傳報SSL: CERTIFICATE_VERIFY_FAILED]

本文不僅講的是如何解決使用七牛sdk中所遇到的問題,並由此引申出在遇到該底層報錯時不同python環境下的解決辦法

問題描述:底層報錯為ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed ,表示該請求證書驗證失敗。

  pep476中詳細描述了該問題的前因後果,python ssl的證書驗證依賴於本地的證書資料庫。一般是機器系統本身提供的資料庫,如果找不到資料庫或資料庫中沒有匹配的證書,將會是一個錯誤,需要使用者定位來修復它。
  PEP建議使用系統提供的證書資料庫,OpenSSL中的一對環境變數SSL_CERT_DIR和SSL_CERT_FILE,可將Python指向不同的證書資料庫。

在檔案頂端新增如下程式碼

import ssl

try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    # Legacy Python that doesn't verify HTTPS certificates by default
    pass
else:
    # Handle target environment that doesn't support HTTPS verification
    ssl._create_default_https_context = _create_unverified_https_context

  上述程式碼建立了一個未驗證的上下文來訪問https連結,這會全域性禁用證書驗證,儘管危險,但這是簡單的解決辦法。該方法等同於在urllib2.urlopen方法中將context引數賦值為ssl._create_unverified_context(),requests庫的方法中將verify引數設定為false,都是關閉證書驗證的原理。
  示例如下

import ssl
context = ssl._create_unverified_context()
urllib.urlopen("https://no-valid-cert", context=context)

當然,最好是可以選擇驗證的證書, 在requests庫裡,單獨的一個請求可以這樣寫

requests.get('https://github.com', verify='/path/to/certfile')

持久化的情況下,session要驗證的證書可以這樣寫

s = requests.Session()
s.verify = '/path/to/certfile'

  verify引數的值可以是證書檔案或目錄,如果是目錄必須使用OpenSSL中的c_rehash處理後才行。

  對於urllib庫,同樣的方法,傳入指定證書或context

  requests中的證書庫用的是Mozilla trust store,並不是很全,只隨requests版本的更新而更新,這也是requests庫經常報錯的原因。可以選擇繫結其他的證書庫如Trust Database for Humans或及時升級certifi庫。選擇繫結的環境變數為REQUESTS_CA_BUNDLE,程式碼例子如

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

  證書的路徑可以直接在命令列輸入“python -c “import requests; print requests.certs.where()”得到,如下圖
這裡寫圖片描述

  也可以找到requests庫下的證書檔案,對其進行更改。在cacert.pem檔案結尾貼上你網站的域名證書。

from requests.utils import DEFAULT_CA_BUNDLE_PATH; 

print(DEFAULT_CA_BUNDLE_PATH)

得到檔案路徑如
(/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/requests/cacert.pem),然後對其進行編輯。這裡寫圖片描述

  如果是在OSX用的Python 3.6,沒有certificates。使用者可以直接執行命令“/Applications/Python\ 3.6/Install\ Certificates.command”。
該命令會更新certifi庫,並將原有的openssl_cafile檔案刪除,重新連結一個新的openssl_cafile檔案。下的Notes on this release第六條macOS users。

  總之出現該報錯,解決的思路就是更新或指定證書庫,網上可以找到許多方法對證書進行更新。
  當然,上面建立的context可以通過猴子補丁(執行是修改替換庫)新增到Python標準操作環境中的sitecustomize.py。建議安全敏感的應用程式應該運用該方法提供始終明確的人為指定的SSL上下文context,而不是依賴於Python的預設行為。

  如果仍是未能解決,針對七牛上傳的sdk的報錯,可以修改sdk中上傳域名變數“host”,將其改為對應區域的http協議的上傳域名。該方法一是不能自動適應多個區域,二是沒法走https,三是七牛如果修改上傳域名就會導致錯誤,只能是臨時的解決辦法。
  如 空間屬於華東區域,將sdk內的所有上傳域名host變數賦值為http://up.qiniu.com

這裡寫圖片描述