MacOS升級到Monterey 12.0.1後,忽然發現原來工作正常的python3請求華為restconf API報錯失敗,提示 ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1129) ,mac自帶的curl也與huawei API握手失敗,提示 curl: (35) error:06FFF089:digital envelope routines:CRYPTO_internal:bad key length 。
mac平臺上預設使用的是libressl而不是openssl,ssl版本資訊:LibreSSL 2.8.3,curl版本資訊:curl 7.77.0 (x86_64-apple-darwin21.0) libcurl/7.77.0 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.42.0。
抓包檢視ssl握手過程,發現curl和python3的表現還不太一樣。
上圖是curl的握手過程,可以看到已經完成了key exchnge,但是客戶端不知什麼原因主動關閉了連線,之後是服務端報錯。
上圖是python3呼叫http.client.HTTPSConnection庫的握手互動,可以看到剛剛發出client hello,服務端就直接報錯。
同樣是python3,在linux上就毫無問題,mac上的python3與其他https網站握手也沒問題。對比linux上和mac上握手抓包可以看到,mac發出的client hello中多出一些欄位,與華為技術溝通後表示,huawei的restconf API不支援tls1.3協議,他認為這是握手失敗的原因。
可以看到linux上ssl雖然也支援tls1.3,但是握手過程中沒有這個supported_versions的extension,嘗試在python中設定禁止tls1.3,測試結果握手成功。
解決方法如下:
from ssl import _create_unverified_context
ctx = _create_unverified_context() ctx.set_ciphers('ALL') ctx.options &= ~ssl.OP_NO_SSLv3 #允許ssl3.0,預設禁止的 ctx.options |= ssl.OP_NO_TLSv1_3 #禁止tls1.3,預設允許 opener = HTTPSConnection('xx.xx.xx.xx', port=443, timeout=3, context=ctx)
使用urllib3或者request庫的也可以參考這裡修改context。
以上辦法在python3.2以後版本中支援,python3.2以前的版本也可以使用下面的辦法:
ctx = _create_unverified_context(ssl.PROTOCOL_TLSv1_2)
這個常量已經在python3.6版本後刪除了,只能使用前面的辦法。
遺憾的是,curl失敗的問題還沒找到解決辦法,看網上也很多人在等待蘋果修復。
如果覺得本文對您有幫助,請掃描後面的二維碼給予捐贈,您的支援是作者繼續寫出更好文章的動力!