ssl --- 套接字對(duì)象的TLS/SSL封裝?
源代碼: Lib/ssl.py
本模塊保證了對(duì)傳安全傳輸層協(xié)議(TLS)的訪問 (SSL)加密,并且提供客戶端和服務(wù)端層面的網(wǎng)絡(luò)嵌套字層面的對(duì)等連接認(rèn)證技術(shù)。本模塊使用OpenSSL庫。適用于所有現(xiàn)代Unix系統(tǒng)、Windows以及Mac OS X。只要Open SSL存在的系統(tǒng),都有機(jī)會(huì)正常使用。
注解
某些行為可能具有平臺(tái)依賴,因?yàn)檎{(diào)用是根據(jù)操作系統(tǒng)的嵌套字API。不同版本的Open SSL也會(huì)引起差異:例如Open SSL版本1.0.1 自帶TLSv1.1 和 TLSv1.2
警告
在閱讀 安全考量 前不要使用此模塊。 這樣做可能會(huì)導(dǎo)致虛假的安全感,因?yàn)閟sl模塊的默認(rèn)設(shè)置不一定適合你的應(yīng)用程序。
本文檔記錄"ssl"模塊的對(duì)象和函數(shù);更多關(guān)于TLS,SSL,和證書的信息,請(qǐng)參閱下方的“詳情”選項(xiàng)
本模塊提供了一個(gè)類 ssl.SSLSocket,它派生自 socket.socket 類型,并提供類似套接字的包裝器,也能夠?qū)νㄟ^帶 SSL 套接字的數(shù)據(jù)進(jìn)行加密和解密。 它支持一些額外方法例如 getpeercert(),該方法可從連接的另一端獲取證書,還有 cipher(),該方法可獲取安全連接所使用的密碼。
對(duì)于更復(fù)雜的應(yīng)用程序,ssl.SSLContext 類有助于管理設(shè)置項(xiàng)和證書,進(jìn)而可以被使用 SSLContext.wrap_socket() 方法創(chuàng)建的 SSL 套接字繼承。
在 3.5.3 版更改: 更新以支持和 OpenSSL 1.1.0 的鏈接
在 3.6 版更改: OpenSSL 0.9.8、1.0.0 和 1.0.1 已過時(shí),將不再被支持。在 ssl 模塊未來的版本中,最低需要 OpenSSL 1.0.2 或 1.1.0。
方法、常量和異常處理?
套接字創(chuàng)建?
從 Python 3.2 和 2.7.9 開始,建議使用 SSLContext 實(shí)例的 SSLContext.wrap_socket() 來將套接字包裝為 SSLSocket 對(duì)象。 輔助函數(shù) create_default_context() 會(huì)返回一個(gè)新的帶有安全默認(rèn)設(shè)置的上下文。 舊的 wrap_socket() 函數(shù)已被棄用,因?yàn)樗瘦^差并且不支持服務(wù)器名稱提示(SNI)和主機(jī)匹配。
客戶端套接字實(shí)例,采用默認(rèn)上下文和IPv4/IPv6雙棧:
import socket
import ssl
hostname = 'www.python.org'
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print(ssock.version())
客戶端套接字示例,帶有自定義上下文和IPv4:
hostname = 'www.python.org'
# PROTOCOL_TLS_CLIENT requires valid cert chain and hostname
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_verify_locations('path/to/cabundle.pem')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print(ssock.version())
服務(wù)器套接字實(shí)例,在localhost上監(jiān)聽IPv4:
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('/path/to/certchain.pem', '/path/to/private.key')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
sock.bind(('127.0.0.1', 8443))
sock.listen(5)
with context.wrap_socket(sock, server_side=True) as ssock:
conn, addr = ssock.accept()
...
上下文創(chuàng)建?
便捷函數(shù),可以幫助創(chuàng)建 SSLContext 對(duì)象,用于常見的目的。
-
ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)? 返回一個(gè)新的
SSLContext對(duì)象,使用給定 purpose 的默認(rèn)設(shè)置。 該設(shè)置由ssl模塊選擇,并且通常是代表一個(gè)比直接調(diào)用SSLContext構(gòu)造器時(shí)更高的安全等級(jí)。cafile, capath, cadata 代表用于進(jìn)行證書核驗(yàn)的可選受信任 CA 證書,與
SSLContext.load_verify_locations()的一致。 如果三個(gè)參數(shù)均為None,此函數(shù)可以轉(zhuǎn)而選擇信任系統(tǒng)的默認(rèn) CA 證書。設(shè)置為:
PROTOCOL_TLS,OP_NO_SSLv2和OP_NO_SSLv3,帶有不含 RC4 及未認(rèn)證的高強(qiáng)度加密密碼套件。 傳入SERVER_AUTH作為 purpose 會(huì)將verify_mode設(shè)為CERT_REQUIRED并加載 CA 證書 (若給出 cafile, capath 或 cadata 之一) 或用SSLContext.load_default_certs()加載默認(rèn) CA 證書。注解
協(xié)議、選項(xiàng)、密碼和其他設(shè)置可隨時(shí)更改為更具約束性的值而無須事先棄用。 這些值代表了兼容性和安全性之間的合理平衡。
如果你的應(yīng)用需要特定的設(shè)置,你應(yīng)當(dāng)創(chuàng)建一個(gè)
SSLContext并自行應(yīng)用設(shè)置。注解
如果你發(fā)現(xiàn)當(dāng)某些較舊的客戶端或服務(wù)器嘗試與用此函數(shù)創(chuàng)建的
SSLContext進(jìn)行連接時(shí)收到了報(bào)錯(cuò)提示 "Protocol or cipher suite mismatch",這可能是因?yàn)樗鼈冎恢С?SSL3.0 而它被此函數(shù)用OP_NO_SSLv3排除掉了。 SSL3.0 被廣泛認(rèn)為 完全不可用。 如果你仍希望繼續(xù)使用此函數(shù)但仍允許 SSL 3.0 連接,你可以使用以下代碼重新啟用它們:ctx = ssl.create_default_context(Purpose.CLIENT_AUTH) ctx.options &= ~ssl.OP_NO_SSLv3
3.4 新版功能.
在 3.4.4 版更改: RC4 被從默認(rèn)密碼字符串中丟棄。
在 3.6 版更改: ChaCha20/Poly1305 被添加到默認(rèn)密碼字符串中。
3DES 被從默認(rèn)密碼字符串中丟棄。
異常?
-
exception
ssl.SSLError? 引發(fā)此異常以提示來自下層 SSL 實(shí)現(xiàn)(目前由 OpenSSL 庫提供)的錯(cuò)誤。 它表示在下層網(wǎng)絡(luò)連接之上疊加的高層級(jí)加密和驗(yàn)證層存在某種問題。 此錯(cuò)誤是
OSError的一個(gè)子類型。SSLError實(shí)例的錯(cuò)誤和消息是由 OpenSSL 庫提供的。在 3.3 版更改:
SSLError曾經(jīng)是socket.error的一個(gè)子類型。-
library? 一個(gè)字符串形式的助詞符,用來指明發(fā)生錯(cuò)誤的 OpenSSL 子模塊,例如
SSL,PEM或X509。 可能的取值范圍依賴于 OpenSSL 的版本。3.3 新版功能.
-
reason? 一個(gè)字符串形式的助記符,用來指明發(fā)生錯(cuò)誤的原因,例如
CERTIFICATE_VERIFY_FAILED。 可能的取值范圍依賴于 OpenSSL 的版本。3.3 新版功能.
-
-
exception
ssl.SSLZeroReturnError? SSLError的一個(gè)子類,當(dāng)嘗試讀取或?qū)懭肭?SSL 連接已被完全關(guān)閉時(shí)會(huì)被引發(fā)。 請(qǐng)注意這并不意味著下層的傳輸(讀取 TCP)已被關(guān)閉。3.3 新版功能.
-
exception
ssl.SSLWantReadError? SSLError的一個(gè)子類,當(dāng)嘗試讀取或?qū)懭氲?,并在?qǐng)求被滿足之前還需要在下層的 TCP 傳輸上接收更多數(shù)據(jù)時(shí)會(huì)被 非阻塞型 SSL 套接字 引發(fā)。3.3 新版功能.
-
exception
ssl.SSLWantWriteError? SSLError的一個(gè)子類,當(dāng)嘗試讀取或?qū)懭霐?shù)據(jù),但在請(qǐng)求被滿足之前還需要在下層的 TCP 傳輸上發(fā)送更多數(shù)據(jù)時(shí)會(huì)被 非阻塞型 SSL 套接字 引發(fā)。3.3 新版功能.
-
exception
ssl.SSLSyscallError? SSLError的子類,當(dāng)嘗試在 SSL 套接字上執(zhí)行操作時(shí)遇到系統(tǒng)錯(cuò)誤時(shí)會(huì)被引發(fā)。 不幸的是,沒有簡單的方式能檢查原始 errno 編號(hào)。3.3 新版功能.
-
exception
ssl.SSLEOFError? SSLError的子類,當(dāng) SSL 連接被突然終止時(shí)會(huì)被引發(fā)。 通常,當(dāng)遇到此錯(cuò)誤時(shí)你不應(yīng)再嘗試重用下層的傳輸。3.3 新版功能.
-
exception
ssl.SSLCertVerificationError? SSLError的子類,當(dāng)證書驗(yàn)證失敗時(shí)會(huì)被引發(fā)。3.7 新版功能.
-
verify_code? 一個(gè)數(shù)字形式的錯(cuò)誤編號(hào),用于表示驗(yàn)證錯(cuò)誤。
-
verify_message? 用于表示驗(yàn)證錯(cuò)誤的人類可讀的字符串。
-
-
exception
ssl.CertificateError? -
在 3.7 版更改: 此異常現(xiàn)在是
SSLCertVerificationError的別名。
隨機(jī)生成?
-
ssl.RAND_bytes(num)? 返回 num 個(gè)高加密強(qiáng)度偽隨機(jī)字節(jié)數(shù)據(jù)。 如果 PRNG 未使用足夠的數(shù)據(jù)作為隨機(jī)種子或者如果當(dāng)前 RAND 方法不支持該操作則會(huì)引發(fā)
SSLError。RAND_status()可被用來檢查 PRNG 的狀態(tài)而RAND_add()可被用來為 PRNG 設(shè)置隨機(jī)種子。對(duì)于幾乎所有應(yīng)用程序都更推薦使用
os.urandom()。Read the Wikipedia article, Cryptographically secure pseudorandom number generator (CSPRNG), to get the requirements of a cryptographically generator.
3.3 新版功能.
-
ssl.RAND_pseudo_bytes(num)? 返回 (bytes, is_cryptographic): bytes 是 num 個(gè)偽隨機(jī)字節(jié)數(shù)據(jù),如果所生成的字節(jié)數(shù)據(jù)為高加密強(qiáng)度則 is_cryptographic 為
True。 如果當(dāng)前 RAND 方法不支持此操作則會(huì)引發(fā)SSLError。所生成的偽隨機(jī)字節(jié)序列如果具有足夠的長度則將會(huì)具有唯一性,并是并非不可預(yù)測。 它們可被用于非加密目的以及加密協(xié)議中的特定目的,但通常不可被用于密鑰生成等目的。
對(duì)于幾乎所有應(yīng)用程序都更推薦使用
os.urandom()。3.3 新版功能.
3.6 版后已移除: OpenSSL 已棄用了
ssl.RAND_pseudo_bytes(),請(qǐng)改用ssl.RAND_bytes()。
-
ssl.RAND_status()? 如果 SSL 偽隨機(jī)數(shù)生成器已使用‘足夠的’隨機(jī)性作為種子則返回
True,否則返回False。 你可以使用ssl.RAND_egd()和ssl.RAND_add()來增加偽隨機(jī)數(shù)生成器的隨機(jī)性。
-
ssl.RAND_egd(path)? 如果你在某處運(yùn)行了一個(gè)熵收集守護(hù)程序(EGD),且 path 是向其打開的套接字連接路徑名,此函數(shù)將從該套接字讀取 256 個(gè)字節(jié)的隨機(jī)性數(shù)據(jù),并將其添加到 SSL 偽隨機(jī)數(shù)生成器以增加所生成密鑰的安全性。 此操作通常只在沒有更好隨機(jī)性源的系統(tǒng)上才是必要的。
請(qǐng)查看 http://egd.sourceforge.net/ 或 http://prngd.sourceforge.net/ 來了解有關(guān)熵收集守護(hù)程序源的信息。
可用性: 對(duì)于 LibreSSL 和 OpenSSL > 1.1.0 不可用。
-
ssl.RAND_add(bytes, entropy)? 將給定的 bytes 混合到 SSL 偽隨機(jī)數(shù)生成器中。 形參 entropy (float 類型) 是數(shù)據(jù)所包含的熵的下界 (因此你可以總是使用
0.0)。 請(qǐng)查看 RFC 1750 了解有關(guān)熵源的更多信息。在 3.5 版更改: 現(xiàn)在支持可寫的 字節(jié)類對(duì)象。
證書處理?
-
ssl.match_hostname(cert, hostname)? 驗(yàn)證 cert (使用
SSLSocket.getpeercert()所返回的已解碼格式) 是否匹配給定的 hostname。 所應(yīng)用的規(guī)則是在 RFC 2818, RFC 5280 和 RFC 6125 中描述的檢查 HTTPS 服務(wù)器身份的規(guī)則。 除了 HTTPS,此函數(shù)還應(yīng)當(dāng)適用于各種基于 SSL 協(xié)議的服務(wù)器身份檢查操作,例如 FTPS, IMAPS, POPS 等等。失敗時(shí)引發(fā)
CertificateError。 成功時(shí)此函數(shù)無返回值:>>> cert = {'subject': ((('commonName', 'example.com'),),)} >>> ssl.match_hostname(cert, "example.com") >>> ssl.match_hostname(cert, "example.org") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/py3k/Lib/ssl.py", line 130, in match_hostname ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'
3.2 新版功能.
在 3.3.3 版更改: 此函數(shù)現(xiàn)在遵循 RFC 6125, 6.4.3 小節(jié),它不會(huì)匹配多個(gè)通配符 (例如
*.*.com或*a*.example.org) 也不匹配國際化域名 (IDN) 片段內(nèi)部的通配符。 IDN A 標(biāo)簽例如www*.xn--pthon-kva.org仍然受支持,但x*.python.org不再能匹配xn--tda.python.org。在 3.5 版更改: 現(xiàn)在支持匹配存在于證書的 subjectAltName 字段中的 IP 地址。
在 3.7 版更改: 此函數(shù)不再被用于 TLS 連接。 主機(jī)匹配現(xiàn)在是由 OpenSSL 執(zhí)行的。
允許位于段的最左端且為唯一字符的通配符。 部分通配符例如
www*.example.com已不再受支持。3.7 版后已移除.
-
ssl.cert_time_to_seconds(cert_time)? 返回距離 Unix 紀(jì)元零時(shí)的秒數(shù),給定的
cert_time字符串代表來自證書的 "notBefore" 或 "notAfter" 日期值,采用"%b %d %H:%M:%S %Y %Z"strptime 格式(C 區(qū)域)。以下為示例代碼:
>>> import ssl >>> timestamp = ssl.cert_time_to_seconds("Jan 5 09:34:43 2018 GMT") >>> timestamp 1515144883 >>> from datetime import datetime >>> print(datetime.utcfromtimestamp(timestamp)) 2018-01-05 09:34:43
"notBefore" 或 "notAfter" 日期值必須使用 GMT (RFC 5280)。
在 3.5 版更改: 將輸入時(shí)間解讀為 UTC 時(shí)間,基于輸入字符串中指明的 'GMT' 時(shí)區(qū)。 在之前使用的是本地時(shí)區(qū)。 返回一個(gè)整數(shù)(不帶輸入格式中秒的分?jǐn)?shù)部分)
-
ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)? 帶 SSL 保護(hù)的服務(wù)器的地址
addr以 (hostname, port-number) 對(duì)的形式給出,獲取服務(wù)器的證書,并將其以 PEM 編碼字符串的形式返回。 如果指定了ssl_version,則使用該版本的 SSL 協(xié)議嘗試連接服務(wù)器。 如果指定了ca_certs,它應(yīng)當(dāng)是一個(gè)包含根證書列表的文件,使用與SSLContext.wrap_socket()中同名形參一致的格式。 該調(diào)用將嘗試根據(jù)指定的根證書集來驗(yàn)證服務(wù)器證書,如果驗(yàn)證失敗則該調(diào)用也將失敗。在 3.3 版更改: 此函數(shù)現(xiàn)在是 IPv6 兼容的。-compatible.
在 3.5 版更改: 默認(rèn)的 ssl_version 從
PROTOCOL_SSLv3改為PROTOCOL_TLS以保證與現(xiàn)代服務(wù)器的最大兼容性。
-
ssl.DER_cert_to_PEM_cert(DER_cert_bytes)? 根據(jù)給定的 DER 編碼字節(jié)塊形式的證書,返回同一證書的 PEM 編碼字符串版本。
-
ssl.PEM_cert_to_DER_cert(PEM_cert_string)? 根據(jù)給定的 ASCII PEM 字符串形式的證書,返回同一證書的 DER 編碼字節(jié)序列。
-
ssl.get_default_verify_paths()? 返回包含 OpenSSL 的默認(rèn) cafile 和 capath 的路徑的命名元組。 此路徑與
SSLContext.set_default_verify_paths()所使用的相同。 返回值是一個(gè) named tupleDefaultVerifyPaths:cafile- 解析出的 cafile 路徑或者如果文件不存在則為None,capath- 解析出的 capath 路徑或者如果目錄不存在則為None,openssl_cafile_env- 指向一個(gè) cafile 的 OpenSSL 環(huán)境鍵,openssl_cafile- 一個(gè) cafile 的硬編碼路徑,openssl_capath_env- 指向一個(gè) capath 的 OpenSSL 環(huán)境鍵,openssl_capath- 一個(gè) capath 目錄的硬編碼路徑
可用性: LibreSSL 會(huì)忽略環(huán)境變量
openssl_cafile_env和openssl_capath_env。3.4 新版功能.
-
ssl.enum_certificates(store_name)? 從 Windows 的系統(tǒng)證書庫中檢索證書。 store_name 可以是
CA,ROOT或MY中的一個(gè)。 Windows 也可能會(huì)提供額外的證書庫。此函數(shù)返回一個(gè)包含 (cert_bytes, encoding_type, trust) 元組的列表。 encoding_type 指明 cert_bytes 的編碼格式。 它可以為
x509_asn以表示 X.509 ASN.1 數(shù)據(jù)或是pkcs_7_asn以表示 PKCS#7 ASN.1 數(shù)據(jù)。 trust 以 OIDS 集合的形式指明證書的目的,或者如果證書對(duì)于所有目的都可以信任則為True。示例:
>>> ssl.enum_certificates("CA") [(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}), (b'data...', 'x509_asn', True)]
可用性: Windows。
3.4 新版功能.
-
ssl.enum_crls(store_name)? Windows 的系統(tǒng)證書庫中檢索 CRL。 store_name 可以是
CA,ROOT或MY中的一個(gè)。 Windows 也可能會(huì)提供額外的證書庫。此函數(shù)返回一個(gè)包含 (cert_bytes, encoding_type, trust) 元組的列表。 encoding_type 指明 cert_bytes 的編碼格式。 它可以為
x509_asn以表示 X.509 ASN.1 數(shù)據(jù)或是pkcs_7_asn以表示 PKCS#7 ASN.1 數(shù)據(jù)。可用性: Windows。
3.4 新版功能.
-
ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)? 接受一個(gè)
socket.socket的實(shí)例sock,并返回一個(gè)ssl.SSLSocket的實(shí)例,該類型是socket.socket的子類型,它將下層的套接字包裝在一個(gè) SSL 上下文中。sock必須是一個(gè)SOCK_STREAM套接字;其他套接字類型不被支持。在內(nèi)部,該函數(shù)會(huì)創(chuàng)建一個(gè)
SSLContext,其協(xié)議版本為 ssl_version 且SSLContext.options設(shè)為 cert_reqs。 如果設(shè)置了 keyfile, certfile, ca_certs 或 ciphers 等形參,則參數(shù)值會(huì)被傳給SSLContext.load_cert_chain(),SSLContext.load_verify_locations()以及SSLContext.set_ciphers()。參數(shù) server_side, do_handshake_on_connect 和 suppress_ragged_eofs 具有與
SSLContext.wrap_socket()相同的含義。3.7 版后已移除: 從 Python 3.2 和 2.7.9 開始,建議使用
SSLContext.wrap_socket()來代替wrap_socket()。 模塊級(jí)函數(shù)的功能受限并且將創(chuàng)建不安全的客戶端套接字,不帶服務(wù)器名稱提示或主機(jī)名匹配。
常量?
所有常量現(xiàn)在都是
enum.IntEnum或enum.IntFlag多項(xiàng)集的成員。3.6 新版功能.
-
ssl.CERT_NONE? SSLContext.verify_mode或wrap_socket()的cert_reqs形參可能的取值。PROTOCOL_TLS_CLIENT除外,這是默認(rèn)的模式。 對(duì)于客戶端套接字,幾乎任何證書都是可接受的。 驗(yàn)證錯(cuò)誤例如不受信任或過期的證書錯(cuò)誤會(huì)被忽略并且不會(huì)中止 TLS/SSL 握手。在服務(wù)器模式下,不會(huì)從客戶端請(qǐng)求任何證書,因此客戶端不會(huì)發(fā)送任何用于客戶端證書身份驗(yàn)證的證書。
參見下文對(duì)于 安全考量 的討論。
-
ssl.CERT_OPTIONAL? SSLContext.verify_mode或wrap_socket()的cert_reqs形參可能的取值。CERT_OPTIONAL具有與CERT_REQUIRED相同的含義。 對(duì)于客戶端套接字推薦改用CERT_REQUIRED。在服務(wù)器模式下,客戶端證書請(qǐng)求會(huì)被發(fā)送給客戶端。 客戶端可以忽略請(qǐng)求也可以發(fā)送一個(gè)證書以執(zhí)行 TLS 客戶端證書身份驗(yàn)證。 如果客戶端選擇發(fā)送證書,則將對(duì)其執(zhí)行驗(yàn)證。 任何驗(yàn)證錯(cuò)誤都將立即中止 TLS 握手。
使用此設(shè)置要求將一組有效的 CA 證書傳遞給
SSLContext.load_verify_locations()或是作為wrap_socket()的ca_certs形參值。
-
ssl.CERT_REQUIRED? SSLContext.verify_mode或wrap_socket()的cert_reqs形參可能的取值。 在此模式下,需要從套接字連接的另一端獲取證書;如果未提供證書或驗(yàn)證失敗則將引發(fā)SSLError。 此模式 不能 在客戶端模式下對(duì)證書進(jìn)行驗(yàn)證,因?yàn)樗粫?huì)匹配主機(jī)名。check_hostname也必須被啟用以驗(yàn)證證書的真實(shí)性。PROTOCOL_TLS_CLIENT會(huì)使用CERT_REQUIRED并默認(rèn)啟用check_hostname。對(duì)于服務(wù)器套接字,此模式會(huì)提供強(qiáng)制性的 TLS 客戶端證書驗(yàn)證。 客戶端證書請(qǐng)求會(huì)被發(fā)送給客戶端并且客戶端必須提供有效且受信任的證書。
使用此設(shè)置要求將一組有效的 CA 證書傳遞給
SSLContext.load_verify_locations()或是作為wrap_socket()的ca_certs形參值。
-
class
ssl.VerifyMode? CERT_* 常量的
enum.IntEnum多項(xiàng)集。3.6 新版功能.
-
ssl.VERIFY_DEFAULT? SSLContext.verify_flags可能的取值。 在此模式下,證書吊銷列表(CRL)并不會(huì)被檢查。 OpenSSL 默認(rèn)不要求也不驗(yàn)證 CRL。3.4 新版功能.
-
ssl.VERIFY_CRL_CHECK_LEAF? Possible value for
SSLContext.verify_flags. In this mode, only the peer cert is checked but none of the intermediate CA certificates. The mode requires a valid CRL that is signed by the peer cert's issuer (its direct ancestor CA). If no proper CRL has has been loaded withSSLContext.load_verify_locations, validation will fail.3.4 新版功能.
-
ssl.VERIFY_CRL_CHECK_CHAIN? SSLContext.verify_flags可能的取值。 在此模式下,會(huì)檢查對(duì)等證書鏈中所有證書的 CRL。3.4 新版功能.
-
ssl.VERIFY_X509_STRICT? SSLContext.verify_flags可能的取值,用于禁用已損壞 X.509 證書的繞過操作。3.4 新版功能.
-
ssl.VERIFY_X509_TRUSTED_FIRST? SSLContext.verify_flags可能的取值。 它指示 OpenSSL 在構(gòu)建用于驗(yàn)證某個(gè)證書的信任鏈時(shí)首選受信任的證書。 此旗標(biāo)將默認(rèn)被啟用。3.4.4 新版功能.
-
class
ssl.VerifyFlags? VERIFY_* 常量的
enum.IntFlag多項(xiàng)集。3.6 新版功能.
-
ssl.PROTOCOL_TLS? 選擇客戶端和服務(wù)器均支持的最高協(xié)議版本。 此選項(xiàng)名稱并不準(zhǔn)確,實(shí)際上 "SSL" 和 "TLS" 協(xié)議均可被選擇。
3.6 新版功能.
-
ssl.PROTOCOL_TLS_CLIENT? 像
PROTOCOL_TLS一樣地自動(dòng)協(xié)商最高協(xié)議版本,但是只支持客戶端SSLSocket連接。 此協(xié)議默認(rèn)會(huì)啟用CERT_REQUIRED和check_hostname。3.6 新版功能.
-
ssl.PROTOCOL_TLS_SERVER? 像
PROTOCOL_TLS一樣地自動(dòng)協(xié)商最高協(xié)議版本,但是只支持服務(wù)器SSLSocket連接。3.6 新版功能.
-
ssl.PROTOCOL_SSLv23? PROTOCOL_TLS的別名。3.6 版后已移除: 請(qǐng)改用
PROTOCOL_TLS。
-
ssl.PROTOCOL_SSLv2? 選擇 SSL 版本 2 作為通道加密協(xié)議。
如果 OpenSSL 編譯時(shí)附帶了
OPENSSL_NO_SSL2旗標(biāo)則此協(xié)議將不可用。警告
SSL 版本 2 并不安全。 極不建議使用它。
3.6 版后已移除: OpenSSL 已經(jīng)移除了對(duì) SSLv2 的支持。
-
ssl.PROTOCOL_SSLv3? 選擇 SSL 版本 3 作為通道加密協(xié)議。
如果 OpenSSL 編譯時(shí)使用了
OPENSSL_NO_SSLv3旗標(biāo)則此協(xié)議將不可用。警告
SSL 版本 3 并不安全。 極不建議使用它。
3.6 版后已移除: OpenSSL 已經(jīng)棄用了所有帶有特定版本號(hào)的協(xié)議。 請(qǐng)改用默認(rèn)協(xié)議
PROTOCOL_TLS并附帶OP_NO_SSLv3等旗標(biāo)。
-
ssl.PROTOCOL_TLSv1? 選擇 TLS 版本 1.0 作為通道加密協(xié)議。
3.6 版后已移除: OpenSSL 已經(jīng)棄用了所有帶有特定版本號(hào)的協(xié)議。 請(qǐng)改用默認(rèn)協(xié)議
PROTOCOL_TLS并附帶OP_NO_SSLv3等旗標(biāo)。
-
ssl.PROTOCOL_TLSv1_1? 選擇 TLS 版本 1.1 作為通道加密協(xié)議。 僅適用于 openssl 版本 1.0.1+。
3.4 新版功能.
3.6 版后已移除: OpenSSL 已經(jīng)棄用了所有帶有特定版本號(hào)的協(xié)議。 請(qǐng)改用默認(rèn)協(xié)議
PROTOCOL_TLS并附帶OP_NO_SSLv3等旗標(biāo)。
-
ssl.PROTOCOL_TLSv1_2? 選譯 TLS 版本 1.2 作為通道加密協(xié)議。 這是最新的版本,也應(yīng)是能提供最大保護(hù)的最佳選擇,如果通信雙方都支持它的話。 僅適用于 openssl 版本 1.0.1+。
3.4 新版功能.
3.6 版后已移除: OpenSSL 已經(jīng)棄用了所有帶有特定版本號(hào)的協(xié)議。 請(qǐng)改用默認(rèn)協(xié)議
PROTOCOL_TLS并附帶OP_NO_SSLv3等旗標(biāo)。
-
ssl.OP_ALL? 對(duì)存在于其他 SSL 實(shí)現(xiàn)中的各種缺陷啟用繞過操作。 默認(rèn)會(huì)設(shè)置此選項(xiàng)。 沒有必要設(shè)置與 OpenSSL 的
SSL_OP_ALL常量同名的旗標(biāo)。3.2 新版功能.
-
ssl.OP_NO_SSLv2? 阻止 SSLv2 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 SSLv2 作為協(xié)議版本。3.2 新版功能.
3.6 版后已移除: SSLv2 已被棄用。
-
ssl.OP_NO_SSLv3? 阻止 SSLv3 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 SSLv3 作為協(xié)議版本。3.2 新版功能.
3.6 版后已移除: SSLv3 已被棄用
-
ssl.OP_NO_TLSv1? 阻止 TLSv1 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 TLSv1 作為協(xié)議版本。3.2 新版功能.
3.7 版后已移除: 此選項(xiàng)自 OpenSSL 1.1.0 起已被棄用,請(qǐng)改用新的
SSLContext.minimum_version和SSLContext.maximum_version。
-
ssl.OP_NO_TLSv1_1? 阻止 TLSv1.1 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 TLSv1.1 作為協(xié)議版本。 僅適用于 openssl 版本 1.0.1+。3.4 新版功能.
3.7 版后已移除: 此選項(xiàng)自 OpenSSL 1.1.0 起已被棄用。
-
ssl.OP_NO_TLSv1_2? 阻止 TLSv1.2 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 TLSv1.2 作為協(xié)議版本。 僅適用于 openssl 版本 1.0.1+。3.4 新版功能.
3.7 版后已移除: 此選項(xiàng)自 OpenSSL 1.1.0 起已被棄用。
-
ssl.OP_NO_TLSv1_3? 阻止 TLSv1.3 連接。 此選項(xiàng)僅可與
PROTOCOL_TLS結(jié)合使用。 它會(huì)阻止對(duì)等方選擇 TLSv1.3 作為協(xié)議版本。 TLS 1.3 適用于 OpenSSL 1.1.1 或更新的版本。 當(dāng) Python 編譯是基于較舊版本的 OpenSSL 時(shí),該旗標(biāo)默認(rèn)為 0。3.7 新版功能.
3.7 版后已移除: 此選項(xiàng)自 OpenSSL 1.1.0 起已被棄用。 它被添加到 2.7.15, 3.6.3 和 3.7.0 是為了向下兼容 OpenSSL 1.0.2。
-
ssl.OP_NO_RENEGOTIATION? 禁用所有 TLSv1.2 和更早版本的重協(xié)商操作。 不發(fā)送 HelloRequest 消息,并忽略通過 ClientHello 發(fā)起的重協(xié)商請(qǐng)求。
此選項(xiàng)僅適用于 OpenSSL 1.1.0h 及更新的版本。
3.7 新版功能.
-
ssl.OP_CIPHER_SERVER_PREFERENCE? 使用服務(wù)器的密碼順序首選項(xiàng),而不是客戶端的首選項(xiàng)。 此選項(xiàng)在客戶端套接字和 SSLv2 服務(wù)器套接字上無效。
3.3 新版功能.
-
ssl.OP_SINGLE_DH_USE? 阻止對(duì)于單獨(dú)的 SSL 會(huì)話重用相同的 DH 密鑰。 這會(huì)提升前向保密性但需要更多的計(jì)算資源。 此選項(xiàng)僅適用于服務(wù)器套接字。
3.3 新版功能.
-
ssl.OP_SINGLE_ECDH_USE? 阻止對(duì)于單獨(dú)的 SSL 會(huì)話重用相同的 ECDH 密鑰。 這會(huì)提升前向保密性但需要更多的計(jì)算資源。 此選項(xiàng)僅適用于服務(wù)器套接字。
3.3 新版功能.
-
ssl.OP_ENABLE_MIDDLEBOX_COMPAT? 在 TLS 1.3 握手中發(fā)送虛擬更改密碼規(guī)格(CCS)消息以使得 TLS 1.3 連接看起來更像是 TLS 1.2 連接。
此選項(xiàng)僅適用于 OpenSSL 1.1.1 及更新的版本。
3.8 新版功能.
-
ssl.OP_NO_COMPRESSION? 在 SSL 通道上禁用壓縮。 這適用于應(yīng)用協(xié)議支持自己的壓縮方案的情況。
此選項(xiàng)僅適用于 OpenSSL 1.0.0 及更新的版本。
3.3 新版功能.
-
class
ssl.Options? OP_* 常量的
enum.IntFlag多項(xiàng)集。
-
ssl.OP_NO_TICKET? 阻止客戶端請(qǐng)求會(huì)話憑據(jù)。
3.6 新版功能.
-
ssl.HAS_ALPN? OpenSSL 庫是否具有對(duì) RFC 7301 中描述的 應(yīng)用層協(xié)議協(xié)商 TLS 擴(kuò)展的內(nèi)置支持。
3.5 新版功能.
-
ssl.HAS_NEVER_CHECK_COMMON_NAME? OpenSSL 庫是否具有對(duì)不檢測目標(biāo)通用名稱的內(nèi)置支持且
SSLContext.hostname_checks_common_name為可寫狀態(tài)。3.7 新版功能.
-
ssl.HAS_ECDH? OpenSSL 庫是否具有對(duì)基于橢圓曲線的 Diffie-Hellman 密鑰交換的內(nèi)置支持。 此常量應(yīng)當(dāng)為真值,除非發(fā)布者明確地禁用了此功能。
3.3 新版功能.
-
ssl.HAS_NPN? OpenSSL 庫是否具有對(duì) 應(yīng)用層協(xié)議協(xié)商 中描述的 下一協(xié)議協(xié)商 的內(nèi)置支持。 當(dāng)此常量為真值時(shí),你可以使用
SSLContext.set_npn_protocols()方法來公告你想要支持的協(xié)議。3.3 新版功能.
-
ssl.HAS_SSLv2? OpenSSL 庫是否具有對(duì) SSL 2.0 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.HAS_SSLv3? OpenSSL 庫是否具有對(duì) SSL 3.0 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.HAS_TLSv1? OpenSSL 庫是否具有對(duì) TLS 1.0 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.HAS_TLSv1_1? OpenSSL 庫是否具有對(duì) TLS 1.1 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.HAS_TLSv1_2? OpenSSL 庫是否具有對(duì) TLS 1.2 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.HAS_TLSv1_3? OpenSSL 庫是否具有對(duì) TLS 1.3 協(xié)議的內(nèi)置支持。
3.7 新版功能.
-
ssl.CHANNEL_BINDING_TYPES? 受支持的 TLS 通道綁定類型組成的列表。 此列表中的字符串可被用作傳給
SSLSocket.get_channel_binding()的參數(shù)。3.3 新版功能.
-
ssl.OPENSSL_VERSION? 解釋器所加載的 OpenSSL 庫的版本字符串:
>>> ssl.OPENSSL_VERSION 'OpenSSL 1.0.2k 26 Jan 2017'
3.2 新版功能.
-
ssl.OPENSSL_VERSION_INFO? 代表 OpenSSL 庫的版本信息的五個(gè)整數(shù)所組成的元組:
>>> ssl.OPENSSL_VERSION_INFO (1, 0, 2, 11, 15)
3.2 新版功能.
-
ssl.OPENSSL_VERSION_NUMBER? OpenSSL 庫的原始版本號(hào),以單個(gè)整數(shù)表示:
>>> ssl.OPENSSL_VERSION_NUMBER 268443839 >>> hex(ssl.OPENSSL_VERSION_NUMBER) '0x100020bf'
3.2 新版功能.
-
ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE? -
ssl.ALERT_DESCRIPTION_INTERNAL_ERROR? -
ALERT_DESCRIPTION_* 來自 RFC 5246 等文檔的警報(bào)描述。 IANA TLS Alert Registry 中包含了這個(gè)列表及對(duì)定義其含義的 RFC 引用。
被用作
SSLContext.set_servername_callback()中的回調(diào)函數(shù)的返回值。3.4 新版功能.
-
class
ssl.AlertDescription? ALERT_DESCRIPTION_* 常量的
enum.IntEnum多項(xiàng)集。3.6 新版功能.
-
Purpose.SERVER_AUTH? create_default_context()和SSLContext.load_default_certs()的選項(xiàng)值。 這個(gè)值表明此上下文可以被用來驗(yàn)證 Web 服務(wù)器(因此,它將被用來創(chuàng)建客戶端套接字)。3.4 新版功能.
-
Purpose.CLIENT_AUTH? create_default_context()和SSLContext.load_default_certs()的選項(xiàng)值。 這個(gè)值表明此上下文可以被用來驗(yàn)證 Web 客戶端(因此,它將被用來創(chuàng)建服務(wù)器端套接字)。3.4 新版功能.
-
class
ssl.SSLErrorNumber? SSL_ERROR_* 常量的
enum.IntEnum多項(xiàng)集。3.6 新版功能.
-
class
ssl.TLSVersion? SSLContext.maximum_version和SSLContext.minimum_version中的 SSL 和 TLS 版本的enum.IntEnum多項(xiàng)集。3.7 新版功能.
-
TLSVersion.MINIMUM_SUPPORTED?
-
TLSVersion.MAXIMUM_SUPPORTED? 受支持的最低和最高 SSL 或 TLS 版本。 這些常量被稱為魔術(shù)常量。 它們的值并不反映可用的最低和最高 TLS/SSL 版本。
-
TLSVersion.SSLv3?
-
TLSVersion.TLSv1?
-
TLSVersion.TLSv1_1?
-
TLSVersion.TLSv1_2?
-
TLSVersion.TLSv1_3? SSL 3.0 至 TLS 1.3。
SSL 套接字?
-
class
ssl.SSLSocket(socket.socket)? SSL 套接字提供了 套接字對(duì)象 的下列方法:
recv(),recv_into()(but passing a non-zeroflagsargument is not allowed)sendfile()(butos.sendfilewill be used for plain-text sockets only, elsesend()will be used)
但是,由于 SSL(和 TLS)協(xié)議在 TCP 之上具有自己的框架,因此 SSL 套接字抽象在某些方面可能與常規(guī)的 OS 層級(jí)套接字存在差異。 特別是要查看 非阻塞型套接字說明。
SSLSocket的實(shí)例必須使用SSLContext.wrap_socket()方法來創(chuàng)建。在 3.5 版更改: 新增了
sendfile()方法。在 3.5 版更改:
shutdown()不會(huì)在每次接收或發(fā)送字節(jié)數(shù)據(jù)后重置套接字超時(shí)。 現(xiàn)在套接字超時(shí)為關(guān)閉的最大總持續(xù)時(shí)間。3.6 版后已移除: 直接創(chuàng)建
SSLSocket實(shí)例的做法已被棄用,請(qǐng)使用SSLContext.wrap_socket()來包裝套接字。在 3.7 版更改:
SSLSocket的實(shí)例必須使用wrap_socket()來創(chuàng)建。 在較早的版本中,直接創(chuàng)建實(shí)例是可能的。 但這從未被記入文檔或是被正式支持。
SSL 套接字還具有下列方法和屬性:
-
SSLSocket.read(len=1024, buffer=None)? 從 SSL 套接字讀取至多 len 個(gè)字節(jié)的數(shù)據(jù)并將結(jié)果作為
bytes實(shí)例返回。 如果指定了 buffer,則改為讀取到緩沖區(qū),并返回所讀取的字節(jié)數(shù)。如果套接字為 非阻塞型 則會(huì)引發(fā)
SSLWantReadError或SSLWantWriteError且讀取將阻塞。由于在任何時(shí)候重新協(xié)商都是可能的,因此調(diào)用
read()也可能導(dǎo)致寫入操作。在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節(jié)數(shù)據(jù)后不會(huì)再被重置。 現(xiàn)在套接字超時(shí)為讀取至多 len 個(gè)字節(jié)數(shù)據(jù)的最大總持續(xù)時(shí)間。
3.6 版后已移除: 請(qǐng)使用
recv()來代替read()。
-
SSLSocket.write(buf)? 將 buf 寫入到 SSL 套接字并返回所寫入的字節(jié)數(shù)。 buf 參數(shù)必須為支持緩沖區(qū)接口的對(duì)象。
如果套接字為 非阻塞型 則會(huì)引發(fā)
SSLWantReadError或SSLWantWriteError且讀取將阻塞。由于在任何時(shí)候重新協(xié)商都是可能的,因此調(diào)用
write()也可能導(dǎo)致讀取操作。在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節(jié)數(shù)據(jù)后不會(huì)再被重置。 現(xiàn)在套接字超時(shí)為寫入 buf 的最大總持續(xù)時(shí)間。
3.6 版后已移除: 請(qǐng)使用
send()來代替write()。
注解
read() 和 write() 方法是讀寫未加密的應(yīng)用級(jí)數(shù)據(jù),并將其解密/加密為帶加密的線路級(jí)數(shù)據(jù)的低層級(jí)方法。 這些方法需要有激活的 SSL 連接,即握手已完成而 SSLSocket.unwrap() 尚未被調(diào)用。
-
SSLSocket.do_handshake()? 執(zhí)行 SSL 設(shè)置握手。
在 3.4 版更改: 當(dāng)套接字的
context的check_hostname屬性為真值時(shí)此握手方法還會(huì)執(zhí)行match_hostname()。在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節(jié)數(shù)據(jù)時(shí)不會(huì)再被重置。 現(xiàn)在套接字超時(shí)為握手的最大總持續(xù)時(shí)間。
在 3.7 版更改: 主機(jī)名或 IP 地址會(huì)在握手期間由 OpenSSL 進(jìn)行匹配。 函數(shù)
match_hostname()將不再被使用。 在 OpenSSL 拒絕主機(jī)名和 IP 地址的情況下,握手將提前被中止并向?qū)Φ确桨l(fā)送 TLS 警告消息。
-
SSLSocket.getpeercert(binary_form=False)? 如果連接另一端的對(duì)等方?jīng)]有證書,則返回
None。 如果 SSL 握手還未完成,則會(huì)引發(fā)ValueError。如果
binary_form形參為False,并且從對(duì)等方接收到了證書,此方法將返回一個(gè)dict實(shí)例。 如果證書未通過驗(yàn)證,則字典將為空。 如果證書通過驗(yàn)證,它將返回由多個(gè)密鑰組成的字典,其中包括subject(證書頒發(fā)給的主體) 和issuer(頒發(fā)證書的主體)。 如果證書包含一個(gè) Subject Alternative Name 擴(kuò)展的實(shí)例 (see RFC 3280),則字典中還將有一個(gè)subjectAltName鍵。subject和issuer字段都是包含在證書中相應(yīng)字段的數(shù)據(jù)結(jié)構(gòu)中給出的相對(duì)專有名稱(RDN)序列的元組,每個(gè) RDN 均為 name-value 對(duì)的序列。 這里是一個(gè)實(shí)際的示例:{'issuer': ((('countryName', 'IL'),), (('organizationName', 'StartCom Ltd.'),), (('organizationalUnitName', 'Secure Digital Certificate Signing'),), (('commonName', 'StartCom Class 2 Primary Intermediate Server CA'),)), 'notAfter': 'Nov 22 08:15:19 2013 GMT', 'notBefore': 'Nov 21 03:09:52 2011 GMT', 'serialNumber': '95F0', 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),), (('countryName', 'US'),), (('stateOrProvinceName', 'California'),), (('localityName', 'San Francisco'),), (('organizationName', 'Electronic Frontier Foundation, Inc.'),), (('commonName', '*.eff.org'),), (('emailAddress', 'hostmaster@eff.org'),)), 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')), 'version': 3}
注解
要驗(yàn)證特定服務(wù)的證書,你可以使用
match_hostname()函數(shù)。如果
binary_form形參為True,并且提供了證書,此方法會(huì)將整個(gè)證書的 DER 編碼形式作為字節(jié)序列返回,或者如果對(duì)等方未提供證書則返回None。 對(duì)等方是否提供證書取決于 SSL 套接字的角色:對(duì)于客戶端 SSL 套接字,服務(wù)器將總是提供證書,無論是否需要進(jìn)行驗(yàn)證;
對(duì)于服務(wù)器 SSL 套接字,客戶端將僅在服務(wù)器要求時(shí)才提供證書;因此如果你使用了
CERT_NONE(而不是CERT_OPTIONAL或CERT_REQUIRED) 則getpeercert()將返回None。
在 3.2 版更改: 返回的字典包括額外的條目例如
issuer和notBefore。在 3.4 版更改: 如果握手未完成則會(huì)引發(fā)
ValueError。 返回的字典包括額外的 X509v3 擴(kuò)展條目例如crlDistributionPoints,caIssuers和OCSPURI。在 3.7.6 版更改: IPv6 地址字符串不再附帶末尾換行符。
-
SSLSocket.cipher()? 返回由三個(gè)值組成的元組,其中包含所使用的密碼名稱,定義其使用方式的 SSL 協(xié)議,以及所使用的加密比特位數(shù)。 如果尚未建立連接,則返回
None。
返回在握手期間由客戶端共享的密碼列表。 所返回列表的每個(gè)條目都是由三個(gè)值組成的元組,其中包括密碼名稱,定義其使用方式的 SSL 協(xié)議版本,以及密碼所使用的加密比特位數(shù)。 如果尚未建立連接或套接字為客戶端套接字則
shared_ciphers()將返回None。3.5 新版功能.
-
SSLSocket.compression()? 以字符串形式返回所使用的壓縮算法,或者如果連接沒有使用壓縮則返回
None。如果高層級(jí)的協(xié)議支持自己的壓縮機(jī)制,你可以使用
OP_NO_COMPRESSION來禁用 SSL 層級(jí)的壓縮。3.3 新版功能.
-
SSLSocket.get_channel_binding(cb_type="tls-unique")? 為當(dāng)前連接獲取字節(jié)串形式的通道綁定數(shù)據(jù)。 如果尚未連接或握手尚未完成則返回
None。cb_type 形參允許選擇需要的通道綁定類型。 有效的通道綁定類型在
CHANNEL_BINDING_TYPES列表中列出。 目前只支持由 RFC 5929 所定義的 'tls-unique' 通道綁定。 如果請(qǐng)求了一個(gè)不受支持的通道綁定類型則將引發(fā)ValueError。3.3 新版功能.
-
SSLSocket.selected_alpn_protocol()? 返回在 TLS 握手期間所選擇的協(xié)議。 如果
SSLContext.set_alpn_protocols()未被調(diào)用,如果另一方不支持 ALPN,如果此套接字不支持任何客戶端所用的協(xié)議,或者如果握手尚未發(fā)生,則將返回None。3.5 新版功能.
-
SSLSocket.selected_npn_protocol()? 返回在Return the higher-level protocol that was selected during the TLS/SSL 握手期間所選擇的高層級(jí)協(xié)議。 如果
SSLContext.set_npn_protocols()未被調(diào)用,或者如果另一方不支持 NPN,或者如果握手尚未發(fā)生,則將返回None。3.3 新版功能.
-
SSLSocket.unwrap()? 執(zhí)行 SSL 關(guān)閉握手,這會(huì)從下層的套接字中移除 TLS 層,并返回下層的套接字對(duì)象。 這可被用來通過一個(gè)連接將加密操作轉(zhuǎn)為非加密。 返回的套接字應(yīng)當(dāng)總是被用于同連接另一方的進(jìn)一步通信,而不是原始的套接字。
-
SSLSocket.verify_client_post_handshake()? 向一個(gè) TLS 1.3 客戶端請(qǐng)求握手后身份驗(yàn)證(PHA)。 只有在初始 TLS 握手之后且雙方都啟用了 PHA 的情況下才能為服務(wù)器端套接字的 TLS 1.3 連接啟用 PHA,參見
SSLContext.post_handshake_auth。此方法不會(huì)立即執(zhí)行證書交換。 服務(wù)器端會(huì)在下一次寫入事件期間發(fā)送 CertificateRequest 并期待客戶端在下一次讀取事件期間附帶證書進(jìn)行響應(yīng)。
如果有任何前置條件未被滿足(例如非 TLS 1.3,PHA 未啟用),則會(huì)引發(fā)
SSLError。注解
僅在 OpenSSL 1.1.1 且 TLS 1.3 被啟用時(shí)可用。 沒有 TLS 1.3 支持,此方法將引發(fā)
NotImplementedError。3.7.1 新版功能.
-
SSLSocket.version()? 以字符串形式返回由連接協(xié)商確定的實(shí)際 SSL 協(xié)議版本,或者如果未建立安全連接則返回
None。 在撰寫本文檔時(shí),可能的返回值包括"SSLv2","SSLv3","TLSv1","TLSv1.1"和"TLSv1.2"。 最新的 OpenSSL 版本可能會(huì)定義更多的返回值。3.5 新版功能.
-
SSLSocket.pending()? 返回在連接上等待被讀取的已解密字節(jié)數(shù)。
-
SSLSocket.context? 此 SSL 套接字所聯(lián)結(jié)的
SSLContext對(duì)象。 如果 SSL 套接字是使用已棄用的wrap_socket()函數(shù) (而非SSLContext.wrap_socket()) 創(chuàng)建的,則這將是為此 SSL 套接字創(chuàng)建的自定義上下文對(duì)象。3.2 新版功能.
-
SSLSocket.server_side? 一個(gè)布爾值,對(duì)于服務(wù)器端套接字為
True而對(duì)于客戶端套接字則為False。3.2 新版功能.
-
SSLSocket.server_hostname? 服務(wù)器的主機(jī)名:
str類型,對(duì)于服務(wù)器端套接字或者如果構(gòu)造器中未指定主機(jī)名則為None。3.2 新版功能.
在 3.7 版更改: 現(xiàn)在該屬性將始終為 ASCII 文本。 當(dāng)
server_hostname為一個(gè)國際化域名(IDN)時(shí),該屬性現(xiàn)在會(huì)保存為 A 標(biāo)簽形式 ("xn--pythn-mua.org") 而非 U 標(biāo)簽形式 ("pyth?n.org")。
-
SSLSocket.session? 用于 SSL 連接的
SSLSession。 該會(huì)話將在執(zhí)行 TLS 握手后對(duì)客戶端和服務(wù)器端套接字可用。 對(duì)于客戶端套接字該會(huì)話可以在調(diào)用do_handshake()之前被設(shè)置以重用一個(gè)會(huì)話。3.6 新版功能.
-
SSLSocket.session_reused? 3.6 新版功能.
SSL 上下文?
3.2 新版功能.
SSL 上下文可保存各種比單獨(dú) SSL 連接壽命更長的數(shù)據(jù),例如 SSL 配置選項(xiàng),證書和私鑰等。 它還可為服務(wù)器端套接字管理緩存,以加快來自相同客戶端的重復(fù)連接。
-
class
ssl.SSLContext(protocol=PROTOCOL_TLS)? 創(chuàng)建一個(gè)新的 SSL 上下文。 你可以傳入 protocol,它必須為此模塊中定義的
PROTOCOL_*常量之一。 該形參指定要使用哪個(gè) SSL 協(xié)議版本。 通常,服務(wù)器會(huì)選擇一個(gè)特定的協(xié)議版本,而客戶端必須適應(yīng)服務(wù)器的選擇。 大多數(shù)版本都不能與其他版本互操作。 如果未指定,則默認(rèn)值為PROTOCOL_TLS;它提供了與其他版本的最大兼容性。這個(gè)表顯示了客戶端(橫向)的哪個(gè)版本能夠連接服務(wù)器(縱向)的哪個(gè)版本。
備注
- 1(1,2)
SSLContext默認(rèn)設(shè)置OP_NO_SSLv2以禁用 SSLv2。- 2(1,2)
SSLContext默認(rèn)設(shè)置OP_NO_SSLv3以禁用 SSLv3。- 3(1,2)
TLS 1.3 協(xié)議在 OpenSSL >= 1.1.1 中設(shè)置
PROTOCOL_TLS時(shí)可用。 沒有專門針對(duì) TLS 1.3 的 PROTOCOL 常量。
參見
create_default_context()讓ssl為特定目標(biāo)選擇安全設(shè)置。在 3.6 版更改: 上下文會(huì)使用安全默認(rèn)值來創(chuàng)建。 默認(rèn)設(shè)置的選項(xiàng)有
OP_NO_COMPRESSION,OP_CIPHER_SERVER_PREFERENCE,OP_SINGLE_DH_USE,OP_SINGLE_ECDH_USE,OP_NO_SSLv2(except forPROTOCOL_SSLv2) 和OP_NO_SSLv3(except forPROTOCOL_SSLv3)。 初始密碼集列表只包含HIGH密碼,不包含NULL密碼和MD5密碼 (PROTOCOL_SSLv2除外)。
SSLContext 對(duì)象具有以下方法和屬性:
-
SSLContext.cert_store_stats()? 獲取以字典表示的有關(guān)已加載的 X.509 證書數(shù)量,被標(biāo)記為 CA 證書的 X.509 證書數(shù)量以及證書吊銷列表的的統(tǒng)計(jì)信息。
具有一個(gè) CA 證書和一個(gè)其他證書的上下文示例:
>>> context.cert_store_stats() {'crl': 0, 'x509_ca': 1, 'x509': 2}
3.4 新版功能.
-
SSLContext.load_cert_chain(certfile, keyfile=None, password=None)? 加載一個(gè)私鑰及對(duì)應(yīng)的證書。 certfile 字符串必須為以 PEM 格式表示的單個(gè)文件路徑,該文件中包含證書以及確立證書真實(shí)性所需的任意數(shù)量的 CA 證書。 如果存在 keyfile 字符串,它必須指向一個(gè)包含私鑰的文件。 否則私鑰也將從 certfile 中提取。 請(qǐng)參閱 證書 中的討論來了解有關(guān)如何將證書存儲(chǔ)至 certfile 的更多信息。
password 參數(shù)可以是一個(gè)函數(shù),調(diào)用時(shí)將得到用于解密私鑰的密碼。 它在私鑰被加密且需要密碼時(shí)才會(huì)被調(diào)用。 它調(diào)用時(shí)將不帶任何參數(shù),并且應(yīng)當(dāng)返回一個(gè)字符串、字節(jié)串或字節(jié)數(shù)組。 如果返回值是一個(gè)字符串,在用它解密私鑰之前它將以 UTF-8 進(jìn)行編碼。 或者也可以直接將字符串、字節(jié)串或字節(jié)數(shù)組值作為 password 參數(shù)提供。 如果私鑰未被加密且不需要密碼則它將被忽略。
如果未指定 password 參數(shù)且需要一個(gè)密碼,將會(huì)使用 OpenSSL 內(nèi)置的密碼提示機(jī)制來交互式地提示用戶輸入密碼。
如果私鑰不能匹配證書則會(huì)引發(fā)
SSLError。在 3.3 版更改: 新增可選參數(shù) password。
-
SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)? 從默認(rèn)位置加載一組默認(rèn)的 "證書頒發(fā)機(jī)構(gòu)" (CA) 證書。 在 Windows 上它將從
CA和ROOT系統(tǒng)存儲(chǔ)中加載 CA 證書。 在其他系統(tǒng)上它會(huì)調(diào)用SSLContext.set_default_verify_paths()。 將來該方法也可能會(huì)從其他位置加載 CA 證書。purpose 旗標(biāo)指明要加載哪一類 CA 證書。 默認(rèn)設(shè)置
Purpose.SERVER_AUTH加載被標(biāo)記且被信任用于 TLS Web 服務(wù)器驗(yàn)證(客戶端套接字)的證書。Purpose.CLIENT_AUTH則加載用于在服務(wù)器端進(jìn)行客戶端證書驗(yàn)證的 CA 證書。3.4 新版功能.
-
SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)? 當(dāng)
verify_mode不為CERT_NONE時(shí)加載一組用于驗(yàn)證其他對(duì)等方證書的 "證書頒發(fā)機(jī)構(gòu)" (CA) 證書。 必須至少指定 cafile 或 capath 中的一個(gè)。此方法還可加載 PEM 或 DER 格式的證書吊銷列表 (CRL),為此必須正確配置
SSLContext.verify_flags。如果存在 cafile 字符串,它應(yīng)為 PEM 格式的級(jí)聯(lián) CA 證書文件的路徑。 請(qǐng)參閱 證書 中的討論來了解有關(guān)如何處理此文件中的證書的更多信息。
如果存在 capath 字符串,它應(yīng)為包含多個(gè) PEM 格式的 CA 證書的目錄的路徑,并遵循 OpenSSL 專屬布局。
如果存在 cadata 對(duì)象,它應(yīng)為一個(gè)或多個(gè) PEM 編碼的證書的 ASCII 字符串或者 DER 編碼的證書的 bytes-like object。 與 capath 一樣 PEM 編碼的證書之外的多余行會(huì)被忽略,但至少要有一個(gè)證書。
在 3.4 版更改: 新增可選參數(shù) cadata
-
SSLContext.get_ca_certs(binary_form=False)? 獲取已離開法人 "證書頒發(fā)機(jī)構(gòu)" (CA) 證書列表。 如果
binary_form形參為False則每個(gè)列表?xiàng)l目都是一個(gè)類似于SSLSocket.getpeercert()輸出的字典。 在其他情況下此方法將返回一個(gè) DER 編碼的證書的列表。 返回的列表不包含來自 capath 的證書,除非 SSL 連接請(qǐng)求并加載了一個(gè)證書。注解
capath 目錄中的證書不會(huì)被加載,除非它們已至少被使用過一次。
3.4 新版功能.
-
SSLContext.get_ciphers()? 獲取已啟用密碼的列表。 該列表將按密碼的優(yōu)先級(jí)排序。 參見
SSLContext.set_ciphers()。示例:
>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) >>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA') >>> ctx.get_ciphers() # OpenSSL 1.0.x [{'alg_bits': 256, 'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA ' 'Enc=AESGCM(256) Mac=AEAD', 'id': 50380848, 'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'protocol': 'TLSv1/SSLv3', 'strength_bits': 256}, {'alg_bits': 128, 'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA ' 'Enc=AESGCM(128) Mac=AEAD', 'id': 50380847, 'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'protocol': 'TLSv1/SSLv3', 'strength_bits': 128}]
在 OpenSSL 1.1 及更新的版本中密碼字典會(huì)包含額外的字段:
>>> ctx.get_ciphers() # OpenSSL 1.1+ [{'aead': True, 'alg_bits': 256, 'auth': 'auth-rsa', 'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA ' 'Enc=AESGCM(256) Mac=AEAD', 'digest': None, 'id': 50380848, 'kea': 'kx-ecdhe', 'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'protocol': 'TLSv1.2', 'strength_bits': 256, 'symmetric': 'aes-256-gcm'}, {'aead': True, 'alg_bits': 128, 'auth': 'auth-rsa', 'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA ' 'Enc=AESGCM(128) Mac=AEAD', 'digest': None, 'id': 50380847, 'kea': 'kx-ecdhe', 'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'protocol': 'TLSv1.2', 'strength_bits': 128, 'symmetric': 'aes-128-gcm'}]
可用性: OpenSSL 1.0.2+。
3.6 新版功能.
-
SSLContext.set_default_verify_paths()? 從構(gòu)建 OpenSSL 庫時(shí)定義的文件系統(tǒng)路徑中加載一組默認(rèn)的 "證書頒發(fā)機(jī)構(gòu)" (CA) 證書。 不幸的是,沒有一種簡單的方式能知道此方法是否執(zhí)行成功:如果未找到任何證書也不會(huì)返回錯(cuò)誤。 不過,當(dāng) OpenSSL 庫是作為操作系統(tǒng)的一部分被提供時(shí),它的配置應(yīng)當(dāng)是正確的。
-
SSLContext.set_ciphers(ciphers)? 為使用此上下文創(chuàng)建的套接字設(shè)置可用密碼。 它應(yīng)當(dāng)為 OpenSSL 密碼列表格式 的字符串。 如果沒有可被選擇的密碼(由于編譯時(shí)選項(xiàng)或其他配置禁止使用所指定的任何密碼),則將引發(fā)
SSLError。注解
在連接后,SSL 套接字的
SSLSocket.cipher()方法將給出當(dāng)前所選擇的密碼。在默認(rèn)情況下 OpenSSL 1.1.1 會(huì)啟用 TLS 1.3 密碼套件。 該套件不能通過
set_ciphers()來禁用。
-
SSLContext.set_alpn_protocols(protocols)? 指定在 SSL/TLS 握手期間套接字應(yīng)當(dāng)通告的協(xié)議。 它應(yīng)為由 ASCII 字符串組成的列表,例如
['http/1.1', 'spdy/2'],按首選順序排列。 協(xié)議的選擇將在握手期間發(fā)生,并依據(jù) RFC 7301 來執(zhí)行。 在握手成功后,SSLSocket.selected_alpn_protocol()方法將返回已達(dá)成一致的協(xié)議。如果
HAS_ALPN為False則此方法將引發(fā)NotImplementedError。當(dāng)雙方都支持 ALPN 但不能就協(xié)議達(dá)成一致時(shí) OpenSSL 1.1.0 至 1.1.0e 將中止并引發(fā)
SSLError。 1.1.0f+ 的行為類似于 1.0.2,SSLSocket.selected_alpn_protocol()返回 None。3.5 新版功能.
-
SSLContext.set_npn_protocols(protocols)? 指定在Specify which protocols the socket should advertise during the SSL/TLS 握手期間套接字應(yīng)當(dāng)通告的協(xié)議。 它應(yīng)為由字符串組成的列表,例如
['http/1.1', 'spdy/2'],按首選順序排列。 協(xié)議的選擇將在握手期間發(fā)生,并將依據(jù) 應(yīng)用層協(xié)議協(xié)商 來執(zhí)行。 在握手成功后,SSLSocket.selected_npn_protocol()方法將返回已達(dá)成一致的協(xié)議。如果
HAS_NPN為False則此方法將引發(fā)NotImplementedError。3.3 新版功能.
-
SSLContext.sni_callback? 注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng) TLS 客戶端指定了一個(gè)服務(wù)器名稱提示時(shí),該回調(diào)函數(shù)將在 SSL/TLS 服務(wù)器接收到 TLS Client Hello 握手消息后被調(diào)用。 服務(wù)器名稱提示機(jī)制的定義見 RFC 6066 section 3 - Server Name Indication。
每個(gè)
SSLContext只能設(shè)置一個(gè)回調(diào)。 如果 sni_callback 被設(shè)置為None則會(huì)禁用回調(diào)。 對(duì)該函數(shù)的后續(xù)調(diào)用將禁用之前注冊(cè)的回調(diào)。此回調(diào)函數(shù)將附帶三個(gè)參數(shù)來調(diào)用;第一個(gè)參數(shù)是
ssl.SSLSocket,第二個(gè)參數(shù)是代表客戶端準(zhǔn)備與之通信的服務(wù)器的字符串 (或者如果 TLS Client Hello 不包含服務(wù)器名稱則為None) 而第三個(gè)參數(shù)是原來的SSLContext。 服務(wù)器名稱參數(shù)為文本形式。 對(duì)于國際化域名,服務(wù)器名稱是一個(gè) IDN A 標(biāo)簽 ("xn--pythn-mua.org")。此回調(diào)的一個(gè)典型用法是將
ssl.SSLSocket的SSLSocket.context屬性修改為一個(gè)SSLContext類型的新對(duì)象,該對(duì)象代表與服務(wù)器相匹配的證書鏈。由于 TLS 連接處于早期協(xié)商階段,因此僅能使用有限的方法和屬性例如
SSLSocket.selected_alpn_protocol()和SSLSocket.context。SSLSocket.getpeercert(),SSLSocket.getpeercert(),SSLSocket.cipher()和SSLSocket.compress()方法要求 TLS 連接已經(jīng)過 TLS Client Hello 因而將既不包含返回有意義的值,也不能安全地調(diào)用它們。sni_callback 函數(shù)必須返回
None以允許 TLS 協(xié)商繼續(xù)進(jìn)行。 如果想要 TLS 失敗,則可以返回常量ALERT_DESCRIPTION_*。 其他返回值將導(dǎo)致 TLS 的致命錯(cuò)誤ALERT_DESCRIPTION_INTERNAL_ERROR.如果從 sni_callback 函數(shù)引發(fā)了異常,則 TLS 連接將終止并發(fā)出 TLS 致命警告消息
ALERT_DESCRIPTION_HANDSHAKE_FAILURE。如果 OpenSSL library 庫在構(gòu)建時(shí)定義了 OPENSSL_NO_TLSEXT 則此方法將返回
NotImplementedError。3.7 新版功能.
-
SSLContext.set_servername_callback(server_name_callback)? 這是被保留用于向下兼容的舊式 API。 在可能的情況下,你應(yīng)當(dāng)改用
sni_callback。 給出的 server_name_callback 類似于 sni_callback,不同之處在于當(dāng)服務(wù)器主機(jī)名是 IDN 編碼的國際化域名時(shí),server_name_callback 會(huì)接收到一個(gè)已編碼的 U 標(biāo)簽 ("pyth?n.org")。如果發(fā)生了服務(wù)器名稱解碼錯(cuò)誤。 TLS 連接將終止并向客戶端發(fā)出
ALERT_DESCRIPTION_INTERNAL_ERROR致命的 TLS 警告消息。3.4 新版功能.
-
SSLContext.load_dh_params(dhfile)? 加載密鑰生成參數(shù)用于 Diffie-Hellman (DH) 密鑰交換。 使用 DH 密鑰交換能以消耗(服務(wù)器和客戶端的)計(jì)算資源為代價(jià)提升前向保密性。 dhfile 參數(shù)應(yīng)當(dāng)為指向一個(gè)包含 PEM 格式的 DH 形參的文件的路徑。
此設(shè)置不會(huì)應(yīng)用于客戶端套接字。 你還可以使用
OP_SINGLE_DH_USE選項(xiàng)來進(jìn)一步提升安全性。3.3 新版功能.
-
SSLContext.set_ecdh_curve(curve_name)? 為基于橢圓曲線的 Elliptic Curve-based Diffie-Hellman (ECDH) 密鑰交換設(shè)置曲線名稱。 ECDH 顯著快于常規(guī) DH 同時(shí)據(jù)信同樣安全。 curve_name 形參應(yīng)為描述某個(gè)知名橢圓曲線的字符串,例如受到廣泛支持的曲線
prime256v1。此設(shè)置不會(huì)應(yīng)用于客戶端套接字。 你還可以使用
OP_SINGLE_ECDH_USE選項(xiàng)來進(jìn)一步提升安全性。如果
HAS_ECDH為False則此方法將不可用。3.3 新版功能.
參見
- SSL/TLS 與完美的前向保密性
Vincent Bernat。
-
SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)? 包裝一個(gè)現(xiàn)有的 Python 套接字 sock 并返回一個(gè)
SSLContext.sslsocket_class的實(shí)例 (默認(rèn)為SSLSocket)。 返回的 SSL 套接字會(huì)綁定上下文、設(shè)置以及證書。 sock 必須是一個(gè)SOCK_STREAM套接字;其他套接字類型不被支持。形參
server_side是一個(gè)布爾值,它標(biāo)明希望從該套接字獲得服務(wù)器端行為還是客戶端行為。對(duì)于客戶端套接字,上下文的構(gòu)造會(huì)延遲執(zhí)行;如果下層的套接字尚未連接,上下文的構(gòu)造將在對(duì)套接字調(diào)用
connect()之后執(zhí)行。 對(duì)于服務(wù)器端套接字,如果套接字沒有遠(yuǎn)端對(duì)等方,它會(huì)被視為一個(gè)監(jiān)聽套接字,并且服務(wù)器端 SSL 包裝操作會(huì)在通過accept()方法所接受的客戶端連接上自動(dòng)執(zhí)行。 此方法可能會(huì)引發(fā)SSLError。在客戶端連接上,可選形參 server_hostname 指定所要連接的服務(wù)的主機(jī)名。 這允許單個(gè)服務(wù)器托管具有單獨(dú)證書的多個(gè)基于 SSL 的服務(wù),很類似于 HTTP 虛擬主機(jī)。 如果 server_side 為真值則指定 server_hostname 將引發(fā)
ValueError。形參
do_handshake_on_connect指明是否要在調(diào)用socket.connect()之后自動(dòng)執(zhí)行 SSL 握手,還是要通過發(fā)起調(diào)用SSLSocket.do_handshake()方法讓應(yīng)用程序顯式地調(diào)用它。 顯式地調(diào)用SSLSocket.do_handshake()可給予程序?qū)ξ帐种兴婕暗奶捉幼?I/O 阻塞行為的控制。形參
suppress_ragged_eofs指明SSLSocket.recv()方法應(yīng)當(dāng)如何從連接的另一端發(fā)送非預(yù)期的 EOF 信號(hào)。 如果指定為True(默認(rèn)值),它將返回正常的 EOF (空字節(jié)串對(duì)象) 來響應(yīng)從下層套接字引發(fā)的非預(yù)期的 EOF 錯(cuò)誤;如果指定為False,它將向調(diào)用方引發(fā)異常。session,參見
session。在 3.5 版更改: 總是允許傳送 server_hostname,即使 OpenSSL 沒有 SNI。
在 3.6 版更改: 增加了 session 參數(shù)。
在 3.7 版更改: 此方法返回
SSLContext.sslsocket_class的實(shí)例而非硬編碼的SSLSocket。
-
SSLContext.sslsocket_class? SSLContext.wrap_socket()的返回類型,默認(rèn)為SSLSocket。 該屬性可以在類實(shí)例上被重載以便返回自定義的SSLSocket的子類。3.7 新版功能.
-
SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)? 包裝 BIO 對(duì)象 incoming 和 outgoing 并返回一個(gè)
SSLContext.sslobject_class(默認(rèn)為SSLObject) 的實(shí)例。 SSL 例程將從 BIO 中讀取輸入數(shù)據(jù)并將數(shù)據(jù)寫入到 outgoing BIO。server_side, server_hostname 和 session 形參具有與
SSLContext.wrap_socket()中相同的含義。在 3.6 版更改: 增加了 session 參數(shù)。
在 3.7 版更改: 此方法返回
SSLContext.sslobject_class的實(shí)例則非硬編碼的SSLObject。
-
SSLContext.sslobject_class? SSLContext.wrap_bio()的返回類型,默認(rèn)為SSLObject。 該屬性可以在類實(shí)例上被重載以便返回自定義的SSLObject的子類。3.7 新版功能.
-
SSLContext.session_stats()? 獲取由此上下文所創(chuàng)建或管理的 SSL 會(huì)話的相關(guān)統(tǒng)計(jì)信息。 返回將每個(gè) 信息片 的名稱映射到其數(shù)字值的字典。 例如,以下是自上下文被創(chuàng)建以來會(huì)話緩存中命中和未命中的總數(shù):
>>> stats = context.session_stats() >>> stats['hits'], stats['misses'] (0, 0)
-
SSLContext.check_hostname? 是否要將對(duì)等方證書的主機(jī)名與
SSLSocket.do_handshake()中的match_hostname()進(jìn)行匹配。 上下文的verify_mode必須被設(shè)為CERT_OPTIONAL或CERT_REQUIRED,并且你必須將 server_hostname 傳給wrap_socket()以便匹配主機(jī)名。 啟用主機(jī)名檢查會(huì)自動(dòng)將 setsverify_mode從CERT_NONE設(shè)置為CERT_REQUIRED。 只要啟用了主機(jī)名檢查就不能將其設(shè)置回CERT_NONE。PROTOCOL_TLS_CLIENT協(xié)議默認(rèn)啟用主機(jī)名檢查。 對(duì)于其他協(xié)議,則必須顯式地啟用主機(jī)名檢查。示例:
import socket, ssl context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True context.load_default_certs() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com') ssl_sock.connect(('www.verisign.com', 443))
3.4 新版功能.
在 3.7 版更改: 現(xiàn)在當(dāng)主機(jī)名檢查被啟用且
verify_mode為CERT_NONE時(shí)verify_mode會(huì)自動(dòng)更改為CERT_REQUIRED。 在之前版本中同樣的操作將失敗并引發(fā)ValueError。注解
此特性要求 OpenSSL 0.9.8f 或更新的版本。
-
SSLContext.maximum_version? 一個(gè)代表所支持的最高 TLS 版本的
TLSVersion枚舉成員。 該值默認(rèn)為TLSVersion.MAXIMUM_SUPPORTED。 這個(gè)屬性對(duì)于PROTOCOL_TLS,PROTOCOL_TLS_CLIENT和PROTOCOL_TLS_SERVER以外的其他協(xié)議來說都是只讀的。maximum_version,minimum_version和SSLContext.options等屬性都會(huì)影響上下文所支持的 SSL 和 TLS 版本。 這個(gè)實(shí)現(xiàn)不會(huì)阻止無效的組合。 例如一個(gè)options為OP_NO_TLSv1_2而maximum_version設(shè)為TLSVersion.TLSv1_2的上下文將無法建立 TLS 1.2 連接。注解
除非 ssl 模塊使用 OpenSSL 1.1.0g 或更新的版本編譯否則這個(gè)屬性將不可用。
3.7 新版功能.
-
SSLContext.minimum_version? 與
SSLContext.maximum_version類似,區(qū)別在于它是所支持的最低版本或?yàn)?TLSVersion.MINIMUM_SUPPORTED。注解
除非 ssl 模塊使用 OpenSSL 1.1.0g 或更新的版本編譯否則這個(gè)屬性將不可用。
3.7 新版功能.
-
SSLContext.options? 一個(gè)代表此上下文中所啟用的 SSL 選項(xiàng)集的整數(shù)。 默認(rèn)值為
OP_ALL,但你也可以通過在選項(xiàng)間進(jìn)行 OR 運(yùn)算來指定其他選項(xiàng)例如OP_NO_SSLv2。注解
對(duì)于 0.9.8m 之前的 OpenSSL 版本,只能設(shè)置選項(xiàng),而不能清除它們。 嘗試(通過重置相應(yīng)比特位)清除選項(xiàng)將會(huì)引發(fā)
ValueError。在 3.6 版更改:
SSLContext.options返回Options旗標(biāo):>>> ssl.create_default_context().options <Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
-
SSLContext.post_handshake_auth? 啟用 TLS 1.3 握手后客戶端身份驗(yàn)證。 握手后驗(yàn)證默認(rèn)是被禁用的,服務(wù)器只能在初始握手期間請(qǐng)求 TLS 客戶端證書。 當(dāng)啟用時(shí),服務(wù)器可以在握手之后的任何時(shí)候請(qǐng)求 TLS 客戶端證書。
當(dāng)在客戶端套接字上啟用時(shí),客戶端會(huì)向服務(wù)器發(fā)信號(hào)說明它支持握手后身份驗(yàn)證。
當(dāng)在服務(wù)器端套接字上啟用時(shí),
SSLContext.verify_mode也必須被設(shè)為CERT_OPTIONAL或CERT_REQUIRED。 實(shí)際的客戶端證書交換會(huì)被延遲直至SSLSocket.verify_client_post_handshake()被調(diào)用并執(zhí)行了一些 I/O 操作后再進(jìn)行。注解
僅在 OpenSSL 1.1.1 且 TLS 1.3 被啟用時(shí)可用。 如果沒有 TLS 1.3 支持,該屬性值將為 None 且不可被更改
3.7.1 新版功能.
-
SSLContext.protocol? 構(gòu)造上下文時(shí)所選擇的協(xié)議版本。 這個(gè)屬性是只讀的。
-
SSLContext.hostname_checks_common_name? 在沒有目標(biāo)替代名稱擴(kuò)展的情況下
check_hostname是否要回退為驗(yàn)證證書的通用名稱(默認(rèn)為真值)。注解
僅在 OpenSSL 1.1.0 或更新的版本上可寫。
3.7 新版功能.
-
SSLContext.verify_flags? 證書驗(yàn)證操作的旗標(biāo)。 你可以通過對(duì)
VERIFY_CRL_CHECK_LEAF等值執(zhí)行 OR 運(yùn)算來設(shè)置組合旗標(biāo)。 在默認(rèn)情況下 OpenSSL 不會(huì)要求也不會(huì)驗(yàn)證證書吊銷列表(CRL)。 僅在 openssl 版本 0.9.8+ 上可用。3.4 新版功能.
在 3.6 版更改:
SSLContext.verify_flags返回VerifyFlags旗標(biāo):>>> ssl.create_default_context().verify_flags <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
-
SSLContext.verify_mode? 是否要嘗試驗(yàn)證其他對(duì)等方的證書以及如果驗(yàn)證失敗應(yīng)采取何種行為。 該屬性值必須為
CERT_NONE,CERT_OPTIONAL或CERT_REQUIRED之一。在 3.6 版更改:
SSLContext.verify_mode返回VerifyMode枚舉:>>> ssl.create_default_context().verify_mode <VerifyMode.CERT_REQUIRED: 2>
證書?
總的來說證書是公鑰/私鑰系統(tǒng)的一個(gè)組成部分。 在這個(gè)系統(tǒng)中,每 個(gè) 主體 (可能是一臺(tái)機(jī)器、一個(gè)人或者一個(gè)組織) 都會(huì)分配到唯一的包含兩部分的加密密鑰。 一部分密鑰是公開的,稱為 公鑰;另一部分密鑰是保密的,稱為 私鑰。 這兩個(gè)部分是互相關(guān)聯(lián)的,就是說如果你用其中一個(gè)部分來加密一條消息,你將能用并且 只能 用另一個(gè)部分來解密它。
在一個(gè)證書中包含有兩個(gè)主體的相關(guān)信息。 它包含 目標(biāo)方 的名稱和目標(biāo)方的公鑰。 它還包含由第二個(gè)主體 頒發(fā)方 所發(fā)布的聲明:目標(biāo)方的身份與他們所宣稱的一致,包含的公鑰也確實(shí)是目標(biāo)方的公鑰。 頒發(fā)方的聲明使用頒發(fā)方的私鑰進(jìn)行簽名,該私鑰的內(nèi)容只有頒發(fā)方自己才知道。 但是,任何人都可以找到頒發(fā)方的公鑰,用它來解密這個(gè)聲明,并將其與證書中的其他信息進(jìn)行比較來驗(yàn)證頒發(fā)方聲明的真實(shí)性。 證書還包含有關(guān)其有效期限的信息。 這被表示為兩個(gè)字段,即 "notBefore" 和 "notAfter"。
在 Python 中應(yīng)用證書時(shí),客戶端或服務(wù)器可以用證書來證明自己的身份。 還可以要求網(wǎng)絡(luò)連接的另一方提供證書,提供的證書可以用于驗(yàn)證以滿足客戶端或服務(wù)器的驗(yàn)證要求。 如果驗(yàn)證失敗,連接嘗試可被設(shè)置為引發(fā)一個(gè)異常。 驗(yàn)證是由下層的 OpenSSL 框架來自動(dòng)執(zhí)行的;應(yīng)用程序本身不必關(guān)注其內(nèi)部的機(jī)制。 但是應(yīng)用程序通常需要提供一組證書以允許此過程的發(fā)生。
Python 使用文件來包含證書。 它們應(yīng)當(dāng)采用 "PEM" 格式 (參見 RFC 1422),這是一種帶有頭部行和尾部行的 base-64 編碼包裝形式:
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----
證書鏈?
包含證書的 Python 文件可以包含一系列的證書,有時(shí)被稱為 證書鏈。 這個(gè)證書鏈應(yīng)當(dāng)以 "作為" 客戶端或服務(wù)器的主體的專屬證書打頭,然后是證書頒發(fā)方的證書,然后是 上述 證書的頒發(fā)方的證書,證書鏈就這樣不斷上溯直到你得到一個(gè) 自簽名 的證書,即具有相同目標(biāo)方和頒發(fā)方的證書,有時(shí)也稱為 根證書。 在證書文件中這些證書應(yīng)當(dāng)被拼接為一體。 例如,假設(shè)我們有一個(gè)包含三個(gè)證書的證書鏈,以我們的服務(wù)器證書打頭,然后是為我們的服務(wù)器證書簽名的證書頒發(fā)機(jī)構(gòu)的證書,最后是為證書頒發(fā)機(jī)構(gòu)的證書頒發(fā)證書的機(jī)構(gòu)的根證書:
-----BEGIN CERTIFICATE-----
... (certificate for your server)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the certificate for the CA)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the root certificate for the CA's issuer)...
-----END CERTIFICATE-----
CA 證書?
如果你想要求對(duì)連接的另一方的證書進(jìn)行驗(yàn)證,你必須提供一個(gè) "CA 證書" 文件,其中包含了你愿意信任的每個(gè)頒發(fā)方的證書鏈。 同樣地,這個(gè)文件的內(nèi)容就是這些證書鏈拼接在一起的結(jié)果。 為了進(jìn)行驗(yàn)證,Python 將使用它在文件中找到的第一個(gè)匹配的證書鏈。 可以通過調(diào)用 SSLContext.load_default_certs() 來使用系統(tǒng)平臺(tái)的證書文件,這可以由 create_default_context() 自動(dòng)完成。
合并的密鑰和證書?
私鑰往往與證書存儲(chǔ)在相同的文件中;在此情況下,只需要將 certfile 形參傳給 SSLContext.load_cert_chain() 和 wrap_socket()。 如果私鑰是與證書一起存儲(chǔ)的,則它應(yīng)當(dāng)放在證書鏈的第一個(gè)證書之前:
-----BEGIN RSA PRIVATE KEY-----
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----
自簽名證書?
如果你準(zhǔn)備創(chuàng)建一個(gè)提供 SSL 加密連接服務(wù)的服務(wù)器,你需要為該服務(wù)獲取一份證書。 有許多方式可以獲取合適的證書,例如從證書頒發(fā)機(jī)構(gòu)購買。 另一種常見做法是生成自簽名證書。 生成自簽名證書的最簡單方式是使用 OpenSSL 軟件包,代碼如下所示:
% openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
Generating a 1024 bit RSA private key
.......++++++
.............................++++++
writing new private key to 'cert.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MyState
Locality Name (eg, city) []:Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.
Organizational Unit Name (eg, section) []:My Group
Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com
Email Address []:ops@myserver.mygroup.myorganization.com
%
自簽名證書的缺點(diǎn)在于它是它自身的根證書,因此不會(huì)存在于別人的已知(且信任的)根證書緩存當(dāng)中。
例子?
檢測 SSL 支持?
要檢測一個(gè) Python 安裝版中是否帶有 SSL 支持,用戶代碼應(yīng)當(dāng)使用以下例程:
try:
import ssl
except ImportError:
pass
else:
... # do something that requires SSL support
客戶端操作?
這個(gè)例子創(chuàng)建了一個(gè) SSL 上下文并使用客戶端套接字的推薦安全設(shè)置,包括自動(dòng)證書驗(yàn)證:
>>> context = ssl.create_default_context()
如果你喜歡自行調(diào)整安全設(shè)置,你可能需要從頭創(chuàng)建一個(gè)上下文(但是請(qǐng)請(qǐng)注意避免不正確的設(shè)置):
>>> context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")
(這段代碼假定你的操作系統(tǒng)將所有 CA 證書打包存放于 /etc/ssl/certs/ca-bundle.crt;如果不是這樣,你將收到報(bào)錯(cuò)信息,必須修改此位置)
PROTOCOL_TLS_CLIENT 協(xié)議配置用于證書驗(yàn)證和主機(jī)名驗(yàn)證的上下文。 verify_mode 設(shè)為 CERT_REQUIRED 而 check_hostname 設(shè)為 True。 所有其他協(xié)議都會(huì)使用不安全的默認(rèn)值創(chuàng)建 SSL 上下文。
當(dāng)你使用此上下文去連接服務(wù)器時(shí),CERT_REQUIRED 和 check_hostname 會(huì)驗(yàn)證服務(wù)器證書;它將確認(rèn)服務(wù)器證書使用了某個(gè) CA 證書進(jìn)行簽名,檢查簽名是否正確,并驗(yàn)證其他屬性例如主機(jī)名的有效性和身份真實(shí)性:
>>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
... server_hostname="www.python.org")
>>> conn.connect(("www.python.org", 443))
你可以隨后獲取該證書:
>>> cert = conn.getpeercert()
可視化檢查顯示證書能夠證明目標(biāo)服務(wù) (即 HTTPS 主機(jī) www.python.org) 的身份:
>>> pprint.pprint(cert)
{'OCSP': ('http://ocsp.digicert.com',),
'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',),
'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl',
'http://crl4.digicert.com/sha2-ev-server-g1.crl'),
'issuer': ((('countryName', 'US'),),
(('organizationName', 'DigiCert Inc'),),
(('organizationalUnitName', 'www.digicert.com'),),
(('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)),
'notAfter': 'Sep 9 12:00:00 2016 GMT',
'notBefore': 'Sep 5 00:00:00 2014 GMT',
'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26',
'subject': ((('businessCategory', 'Private Organization'),),
(('1.3.6.1.4.1.311.60.2.1.3', 'US'),),
(('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),
(('serialNumber', '3359300'),),
(('streetAddress', '16 Allen Rd'),),
(('postalCode', '03894-4801'),),
(('countryName', 'US'),),
(('stateOrProvinceName', 'NH'),),
(('localityName', 'Wolfeboro'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'www.python.org'),)),
'subjectAltName': (('DNS', 'www.python.org'),
('DNS', 'python.org'),
('DNS', 'pypi.org'),
('DNS', 'docs.python.org'),
('DNS', 'testpypi.org'),
('DNS', 'bugs.python.org'),
('DNS', 'wiki.python.org'),
('DNS', 'hg.python.org'),
('DNS', 'mail.python.org'),
('DNS', 'packaging.python.org'),
('DNS', 'pythonhosted.org'),
('DNS', 'www.pythonhosted.org'),
('DNS', 'test.pythonhosted.org'),
('DNS', 'us.pycon.org'),
('DNS', 'id.python.org')),
'version': 3}
現(xiàn)在 SSL 通道已建立并已驗(yàn)證了證書,你可以繼續(xù)與服務(wù)器對(duì)話了:
>>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
>>> pprint.pprint(conn.recv(1024).split(b"\r\n"))
[b'HTTP/1.1 200 OK',
b'Date: Sat, 18 Oct 2014 18:27:20 GMT',
b'Server: nginx',
b'Content-Type: text/html; charset=utf-8',
b'X-Frame-Options: SAMEORIGIN',
b'Content-Length: 45679',
b'Accept-Ranges: bytes',
b'Via: 1.1 varnish',
b'Age: 2188',
b'X-Served-By: cache-lcy1134-LCY',
b'X-Cache: HIT',
b'X-Cache-Hits: 11',
b'Vary: Cookie',
b'Strict-Transport-Security: max-age=63072000; includeSubDomains',
b'Connection: close',
b'',
b'']
參見下文對(duì)于 安全考量 的討論。
服務(wù)器端操作?
對(duì)于服務(wù)器操作,通常你需要在文件中存放服務(wù)器證書和私鑰各一份。 你將首先創(chuàng)建一個(gè)包含密鑰和證書的上下文,這樣客戶端就能檢查你的身份真實(shí)性。 然后你將打開一個(gè)套接字,將其綁定到一個(gè)端口,在其上調(diào)用 listen(),并開始等待客戶端連接:
import socket, ssl
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")
bindsocket = socket.socket()
bindsocket.bind(('myaddr.mydomain.com', 10023))
bindsocket.listen(5)
當(dāng)有客戶端連接時(shí),你將在套接字上調(diào)用 accept() 以從另一端獲取新的套接字,并使用上下文的 SSLContext.wrap_socket() 方法來為連接創(chuàng)建一個(gè)服務(wù)器端 SSL 套接字:
while True:
newsocket, fromaddr = bindsocket.accept()
connstream = context.wrap_socket(newsocket, server_side=True)
try:
deal_with_client(connstream)
finally:
connstream.shutdown(socket.SHUT_RDWR)
connstream.close()
隨后你將從 connstream 讀取數(shù)據(jù)并對(duì)其進(jìn)行處理,直至你結(jié)束與客戶端的會(huì)話(或客戶端結(jié)束與你的會(huì)話):
def deal_with_client(connstream):
data = connstream.recv(1024)
# empty data means the client is finished with us
while data:
if not do_something(connstream, data):
# we'll assume do_something returns False
# when we're finished with client
break
data = connstream.recv(1024)
# finished with client
并返回至監(jiān)聽新的客戶端連接(當(dāng)然,真正的服務(wù)器應(yīng)當(dāng)會(huì)在單獨(dú)的線程中處理每個(gè)客戶端連接,或者將套接字設(shè)為 非阻塞模式 并使用事件循環(huán))。
關(guān)于非阻塞套接字的說明?
在非阻塞模式下 SSL 套接字的行為與常規(guī)套接字略有不同。 當(dāng)使用非阻塞模式時(shí),你需要注意下面這些事情:
如果一個(gè) I/O 操作會(huì)阻塞,大多數(shù)
SSLSocket方法都將引發(fā)SSLWantWriteError或SSLWantReadError而非BlockingIOError。 如果有必要在下層套接字上執(zhí)行讀取操作將引發(fā)SSLWantReadError,在下層套接字上執(zhí)行寫入操作則將引發(fā)SSLWantWriteError。 請(qǐng)注意嘗試 寫入 到 SSL 套接字可能需要先從下層套接字 讀取,而嘗試從 SSL 套接字 讀取 則可能需要先向下層套接字 寫入。在 3.5 版更改: 在較早的 Python 版本中,
SSLSocket.send()方法會(huì)返回零值而非引發(fā)SSLWantWriteError或SSLWantReadError。調(diào)用
select()將告訴你可以從 OS 層級(jí)的套接字讀取(或向其寫入),但這并不意味著在上面的 SSL 層有足夠的數(shù)據(jù)。 例如,可能只有部分 SSL 幀已經(jīng)到達(dá)。 因此,你必須準(zhǔn)備好處理SSLSocket.recv()和SSLSocket.send()失敗的情況,并在再次調(diào)用select()之后重新嘗試。相反地,由于 SSL 層具有自己的幀機(jī)制,一個(gè) SSL 套接字可能仍有可讀取的數(shù)據(jù)而
select()并不知道這一點(diǎn)。 因此,你應(yīng)當(dāng)先調(diào)用SSLSocket.recv()取走所有潛在的可用數(shù)據(jù),然后只在必要時(shí)對(duì)select()調(diào)用執(zhí)行阻塞。(當(dāng)然,類似的保留規(guī)則在使用其他原語例如
poll(),或selectors模塊中的原語時(shí)也適用)SSL 握手本身將是非阻塞的:
SSLSocket.do_handshake()方法必須不斷重試直至其成功返回。 下面是一個(gè)使用select()來等待套接字就緒的簡短例子:while True: try: sock.do_handshake() break except ssl.SSLWantReadError: select.select([sock], [], []) except ssl.SSLWantWriteError: select.select([], [sock], [])
參見
asyncio 模塊支持 非阻塞 SSL 套接字 并提供了更高層級(jí)的 API。 它會(huì)使用 selectors 模塊來輪詢事件并處理 SSLWantWriteError, SSLWantReadError 和 BlockingIOError 等異常。 它還會(huì)異步地執(zhí)行 SSL 握手。
內(nèi)存 BIO 支持?
3.5 新版功能.
自從 SSL 模塊在 Python 2.6 起被引入之后,SSLSocket 類提供了兩個(gè)互相關(guān)聯(lián)但彼此獨(dú)立的功能分塊:
SSL 協(xié)議處理
網(wǎng)絡(luò) IO
網(wǎng)絡(luò) IO API 與 socket.socket 所提供的功能一致,SSLSocket 也是從那里繼承而來的。 這允許 SSL 套接字被用作常規(guī)套接字的替代,使得向現(xiàn)有應(yīng)用程序添加 SSL 支持變得非常容易。
將 SSL 協(xié)議處理與網(wǎng)絡(luò) IO 結(jié)合使用通常都能運(yùn)行良好,但在某些情況下則不能。 此情況的一個(gè)例子是 async IO 框架,該框架要使用不同的 IO 多路復(fù)用模型而非 (基于就緒狀態(tài)的) "在文件描述器上執(zhí)行選擇/輪詢" 模型,該模型是 socket.socket 和內(nèi)部 OpenSSL 套接字 IO 例程正常運(yùn)行的假設(shè)前提。 這種情況在該模型效率不高的 Windows 平臺(tái)上最為常見。 為此還提供了一個(gè) SSLSocket 的簡化形式,稱為 SSLObject。
-
class
ssl.SSLObject? SSLSocket的簡化形式,表示一個(gè)不包含任何網(wǎng)絡(luò) IO 方法的 SSL 協(xié)議實(shí)例。 這個(gè)類通常由想要通過內(nèi)存緩沖區(qū)為 SSL 實(shí)現(xiàn)異步 IO 的框架作者來使用。這個(gè)類在低層級(jí) SSL 對(duì)象上實(shí)現(xiàn)了一個(gè)接口,與 OpenSSL 所實(shí)現(xiàn)的類似。 此對(duì)象會(huì)捕獲 SSL 連接的狀態(tài)但其本身不提供任何網(wǎng)絡(luò) IO。 IO 需要通過單獨(dú)的 "BIO" 對(duì)象來執(zhí)行,該對(duì)象是 OpenSSL 的 IO 抽象層。
這個(gè)類沒有公有構(gòu)造器。
SSLObject實(shí)例必須使用wrap_bio()方法來創(chuàng)建。 此方法將創(chuàng)建SSLObject實(shí)例并將其綁定到一個(gè) BIO 對(duì)。 其中 incoming BIO 用來將數(shù)據(jù)從 Python 傳遞到 SSL 協(xié)議實(shí)例,而 outgoing BIO 用來進(jìn)行數(shù)據(jù)反向傳遞。可以使用以下方法:
與
SSLSocket相比,此對(duì)象缺少下列特性:任何形式的網(wǎng)絡(luò) IO;
recv()和send()僅對(duì)下層的MemoryBIO緩沖區(qū)執(zhí)行讀取和寫入。不存在 do_handshake_on_connect 機(jī)制。 你必須總是手動(dòng)調(diào)用
do_handshake()來開始握手操作。不存在對(duì) suppress_ragged_eofs 的處理。 所有違反協(xié)議的文件結(jié)束條件將通過
SSLEOFError異常來報(bào)告。方法
unwrap()的調(diào)用不返回任何東西,不會(huì)如 SSL 套接字那樣返回下層的套接字。server_name_callback 回調(diào)被傳給
SSLContext.set_servername_callback()時(shí)將獲得一個(gè)SSLObject實(shí)例而非SSLSocket實(shí)例作為其第一個(gè)形參。
有關(guān)
SSLObject用法的一些說明:在
SSLObject上的所有 IO 都是 非阻塞的。 這意味著例如read()在其需要比 incoming BIO 可用的更多數(shù)據(jù)時(shí)將會(huì)引發(fā)SSLWantReadError。不存在模塊層級(jí)的
wrap_bio()調(diào)用,就像wrap_socket()那樣。SSLObject總是通過SSLContext來創(chuàng)建。
在 3.7 版更改:
SSLObject的實(shí)例必須使用wrap_bio()來創(chuàng)建。 在較早的版本中,直接創(chuàng)建實(shí)例是可能的。 但這從未被記入文檔或是被正式支持。
SSLObject 會(huì)使用內(nèi)存緩沖區(qū)與外部世界通信。 MemoryBIO 類提供了可被用于此目的的內(nèi)存緩沖區(qū)。 它包裝了一個(gè) OpenSSL 內(nèi)存 BIO (Basic IO) 對(duì)象:
-
class
ssl.MemoryBIO? 一個(gè)可被用來在 Python 和 SSL 協(xié)議實(shí)例之間傳遞數(shù)據(jù)的內(nèi)存緩沖區(qū)。
-
pending? 返回當(dāng)前存在于內(nèi)存緩沖區(qū)的字節(jié)數(shù)。
-
eof? 一個(gè)表明內(nèi)存 BIO 目前是否位于文件末尾的布爾值。
-
read(n=-1)? 從內(nèi)存緩沖區(qū)讀取至多 n 個(gè)字節(jié)。 如果 n 未指定或?yàn)樨?fù)值,則返回全部字節(jié)數(shù)據(jù)。
-
write(buf)? 將字節(jié)數(shù)據(jù)從 buf 寫入到內(nèi)存 BIO。 buf 參數(shù)必須為支持緩沖區(qū)協(xié)議的對(duì)象。
返回值為寫入的字節(jié)數(shù),它總是與 buf 的長度相等。
-
SSL 會(huì)話?
3.6 新版功能.
安全考量?
最佳默認(rèn)值?
針對(duì) 客戶端使用,如果你對(duì)于安全策略沒有任何特殊要求,則強(qiáng)烈推薦你使用 create_default_context() 函數(shù)來創(chuàng)建你的 SSL 上下文。 它將加載系統(tǒng)的受信任 CA 證書,啟用證書驗(yàn)證和主機(jī)名檢查,并嘗試合理地選擇安全的協(xié)議和密碼設(shè)置。
例如,以下演示了你應(yīng)當(dāng)如何使用 smtplib.SMTP 類來創(chuàng)建指向一個(gè) SMTP 服務(wù)器的受信任且安全的連接:
>>> import ssl, smtplib
>>> smtp = smtplib.SMTP("mail.python.org", port=587)
>>> context = ssl.create_default_context()
>>> smtp.starttls(context=context)
(220, b'2.0.0 Ready to start TLS')
如果連接需要客戶端證書,可使用 SSLContext.load_cert_chain() 來添加。
作為對(duì)比,如果你通過自行調(diào)用 SSLContext 構(gòu)造器來創(chuàng)建 SSL 上下文,它默認(rèn)將不會(huì)啟用證書驗(yàn)證和主機(jī)名檢查。 如果你這樣做,請(qǐng)閱讀下面的段落以達(dá)到良好的安全級(jí)別。
手動(dòng)設(shè)置?
驗(yàn)證證書?
當(dāng)直接調(diào)用 SSLContext 構(gòu)造器時(shí),默認(rèn)會(huì)使用 CERT_NONE。 由于它不會(huì)驗(yàn)證對(duì)等方的身份真實(shí)性,因此是不安全的,特別是在客戶端模式下,大多數(shù)時(shí)候你都希望能保證你所連接的服務(wù)器的身份真實(shí)性。 因此,當(dāng)處于客戶端模式時(shí),強(qiáng)烈推薦使用 CERT_REQUIRED。 但是,光這樣還不夠;你還必須檢查服務(wù)器證書,這可以通過調(diào)用 SSLSocket.getpeercert() 來獲取并匹配目標(biāo)服務(wù)。 對(duì)于許多協(xié)議和應(yīng)用來說,服務(wù)可通過主機(jī)名來標(biāo)識(shí);在此情況下,可以使用 match_hostname() 函數(shù)。 這種通用檢測會(huì)在 SSLContext.check_hostname 被啟用時(shí)自動(dòng)執(zhí)行。
在 3.7 版更改: 主機(jī)名匹配現(xiàn)在是由 OpenSSL 來執(zhí)行的。 Python 不會(huì)再使用 match_hostname()。
在服務(wù)器模式下,如果你想要使用 SSL 層來驗(yàn)證客戶端(而不是使用更高層級(jí)的驗(yàn)證機(jī)制),你也必須要指定 CERT_REQUIRED 并以類似方式檢查客戶端證書。
協(xié)議版本?
SSL 版本 2 和 3 被認(rèn)為是不安全的因而使用它們會(huì)有風(fēng)險(xiǎn)。 如果你想要客戶端和服務(wù)器之間有最大的兼容性,推薦使用 PROTOCOL_TLS_CLIENT 或 PROTOCOL_TLS_SERVER 作為協(xié)議版本。 SSLv2 和 SSLv3 默認(rèn)會(huì)被禁用。
>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.options |= ssl.OP_NO_TLSv1
>>> client_context.options |= ssl.OP_NO_TLSv1_1
前面創(chuàng)建的 SSL 上下文將只允許 TLSv1.2 及更新版本(如果你的系統(tǒng)支持)的服務(wù)器連接。 PROTOCOL_TLS_CLIENT 默認(rèn)會(huì)使用證書驗(yàn)證和主機(jī)名檢查。 你必須將證書加載到上下文中。
密碼選擇?
如果你有更高級(jí)的安全要求,也可以通過 SSLContext.set_ciphers() 方法在協(xié)商 SSL 會(huì)話時(shí)對(duì)所啟用的加密進(jìn)行微調(diào)。 從 Python 3.2.3 開始,ssl 默認(rèn)會(huì)禁用某些較弱的加密,但你還可能希望進(jìn)一步限制加密選項(xiàng)。 請(qǐng)確保仔細(xì)閱讀 OpenSSL 文檔中有關(guān) 加密列表格式 的部分。 如果你想要檢查給定的加密列表啟用了哪些加密,可以使用 SSLContext.get_ciphers() 或所在系統(tǒng)的 openssl ciphers 命令。
多進(jìn)程?
如果使用此模塊作為多進(jìn)程應(yīng)用的一部分(例如使用 multiprocessing 或 concurrent.futures 模塊),請(qǐng)注意 OpenSSL 的內(nèi)部隨機(jī)數(shù)字生成器并不能正確處理分支進(jìn)程。 應(yīng)用程序必須修改父進(jìn)程的 PRNG 狀態(tài),如果它們要使用任何包含 os.fork() 的 SSL 特性的話。 任何對(duì) RAND_add(), RAND_bytes() 或 RAND_pseudo_bytes() 都可以 。
TLS 1.3?
3.7 新版功能.
Python 通過 OpenSSL 1.1.1 提供了臨時(shí)性和實(shí)驗(yàn)性的 TLS 1.3 支持。 這個(gè)新協(xié)議的行為與之前版本的 TLS/SSL 略有不同。 某些新的 TLS 1.3 特性暫時(shí)還不可用。
TLS 1.3 使用一組不同的加密套件集。 默認(rèn)情況下所有 AES-GCM 和 ChaCha20 加密套件都會(huì)被啟用。
SSLContext.set_ciphers()方法還不能啟用或禁用任何 TLS 1.3 加密,但SSLContext.get_ciphers()會(huì)返回它們。會(huì)話憑據(jù)不再會(huì)作為初始握手的組成部分被發(fā)送而是以不同的方式來處理。
SSLSocket.session和SSLSession與 TLS 1.3 不兼容。客戶端證書在初始握手期間也不會(huì)再被驗(yàn)證。 服務(wù)器可以在任何時(shí)候請(qǐng)求證書。 客戶端會(huì)在它們從服務(wù)器發(fā)送或接收應(yīng)用數(shù)據(jù)時(shí)處理證書請(qǐng)求。
早期數(shù)據(jù)、延遲的 TLS 客戶端證書請(qǐng)求、簽名算法配置和密鑰重生成等 TLS 1.3 特性尚未被支持。
LibreSSL 支持?
LibreSSL 是 OpenSSL 1.0.1 的一個(gè)分支。 ssl 模塊包含對(duì) LibreSSL 的有限支持。 當(dāng) ssl 模塊使用 LibreSSL 進(jìn)行編譯時(shí)某些特性將不可用。
LibreSSL >= 2.6.1 不再支持 NPN。
SSLContext.set_npn_protocols()和SSLSocket.selected_npn_protocol()方法將不可用。SSLContext.set_default_verify_paths()會(huì)忽略環(huán)境變量SSL_CERT_FILE和SSL_CERT_PATH,雖然get_default_verify_paths()仍然支持它們。
參見
- Class
socket.socket 下層
socket類的文檔- SSL/TLS 高強(qiáng)度加密:概述
Apache HTTP Server文檔介紹
- RFC 1422: 因特網(wǎng)電子郵件的隱私加強(qiáng):第二部分:基于證書的密鑰管理
Steve Kent
- RFC 4086: 確保安全的隨機(jī)性要求
Donald E., Jeffrey I. Schiller
- RFC 5280: 互聯(lián)網(wǎng) X.509 公鑰基礎(chǔ)架構(gòu)證書和證書吊銷列表 (CRL) 配置文件
D. Cooper
- RFC 5246: 傳輸層安全性 (TLS) 協(xié)議版本 1.2
T. Dierks et. al.
- RFC 6066: 傳輸層安全性 (TLS) 的擴(kuò)展
D. Eastlake
- IANA TLS: 傳輸層安全性 (TLS) 的參數(shù)
IANA
- RFC 7525: 傳輸層安全性 (TLS) 和數(shù)據(jù)報(bào)傳輸層安全性 (DTLS) 的安全使用建議
IETF
- Mozilla 的服務(wù)器端 TLS 建議
Mozilla
