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_SSLv2OP_NO_SSLv3,帶有不含 RC4 及未認(rèn)證的高強(qiáng)度加密密碼套件。 傳入 SERVER_AUTH 作為 purpose 會(huì)將 verify_mode 設(shè)為 CERT_REQUIRED 并加載 CA 證書 (若給出 cafile, capathcadata 之一) 或用 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, PEMX509。 可能的取值范圍依賴于 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?

SSLCertVerificationError 的別名。

在 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 5280RFC 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_versionPROTOCOL_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 tuple DefaultVerifyPaths:

  • 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_envopenssl_capath_env

3.4 新版功能.

ssl.enum_certificates(store_name)?

從 Windows 的系統(tǒng)證書庫中檢索證書。 store_name 可以是 CA, ROOTMY 中的一個(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, ROOTMY 中的一個(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_versionSSLContext.options 設(shè)為 cert_reqs。 如果設(shè)置了 keyfile, certfile, ca_certsciphers 等形參,則參數(shù)值會(huì)被傳給 SSLContext.load_cert_chain(), SSLContext.load_verify_locations() 以及 SSLContext.set_ciphers()。

參數(shù) server_side, do_handshake_on_connectsuppress_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.IntEnumenum.IntFlag 多項(xiàng)集的成員。

3.6 新版功能.

ssl.CERT_NONE?

SSLContext.verify_modewrap_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_modewrap_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_modewrap_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 with SSLContext.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_REQUIREDcheck_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_versionSSLContext.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_SNI?

OpenSSL 庫是否具有對(duì) 服務(wù)器名稱提示 擴(kuò)展(在 RFC 6066 中定義)的內(nèi)置支持。

3.2 新版功能.

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_versionSSLContext.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ì)象 的下列方法:

但是,由于 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ā) SSLWantReadErrorSSLWantWriteError 且讀取將阻塞。

由于在任何時(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ā) SSLWantReadErrorSSLWantWriteError 且讀取將阻塞。

由于在任何時(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)用。

通常你應(yīng)當(dāng)使用套接字 API 方法例如 recv()send() 來代替這些方法。

SSLSocket.do_handshake()?

執(zhí)行 SSL 設(shè)置握手。

在 3.4 版更改: 當(dāng)套接字的 contextcheck_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 鍵。

subjectissuer 字段都是包含在證書中相應(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_OPTIONALCERT_REQUIRED) 則 getpeercert() 將返回 None。

在 3.2 版更改: 返回的字典包括額外的條目例如 issuernotBefore。

在 3.4 版更改: 如果握手未完成則會(huì)引發(fā) ValueError。 返回的字典包括額外的 X509v3 擴(kuò)展條目例如 crlDistributionPoints, caIssuersOCSP URI。

在 3.7.6 版更改: IPv6 地址字符串不再附帶末尾換行符。

SSLSocket.cipher()?

返回由三個(gè)值組成的元組,其中包含所使用的密碼名稱,定義其使用方式的 SSL 協(xié)議,以及所使用的加密比特位數(shù)。 如果尚未建立連接,則返回 None。

SSLSocket.shared_ciphers()?

返回在握手期間由客戶端共享的密碼列表。 所返回列表的每個(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è)版本。

client / server

SSLv2

SSLv3

TLS 3

TLSv1

TLSv1.1

TLSv1.2

SSLv2

no 1

SSLv3

no 2

TLS (SSLv23) 3

no 1

no 2

TLSv1

TLSv1.1

TLSv1.2

備注

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 for PROTOCOL_SSLv2) 和 OP_NO_SSLv3 (except for PROTOCOL_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 上它將從 CAROOT 系統(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) 證書。 必須至少指定 cafilecapath 中的一個(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_ALPNFalse 則此方法將引發(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_NPNFalse 則此方法將引發(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.SSLSocketSSLSocket.context 屬性修改為一個(gè) SSLContext 類型的新對(duì)象,該對(duì)象代表與服務(wù)器相匹配的證書鏈。

由于 TLS 連接處于早期協(xié)商階段,因此僅能使用有限的方法和屬性例如 SSLSocket.selected_alpn_protocol()SSLSocket.contextSSLSocket.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_ECDHFalse 則此方法將不可用。

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ì)象 incomingoutgoing 并返回一個(gè) SSLContext.sslobject_class (默認(rèn)為 SSLObject) 的實(shí)例。 SSL 例程將從 BIO 中讀取輸入數(shù)據(jù)并將數(shù)據(jù)寫入到 outgoing BIO。

server_side, server_hostnamesession 形參具有與 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_OPTIONALCERT_REQUIRED,并且你必須將 server_hostname 傳給 wrap_socket() 以便匹配主機(jī)名。 啟用主機(jī)名檢查會(huì)自動(dòng)將 sets verify_modeCERT_NONE 設(shè)置為 CERT_REQUIRED。 只要啟用了主機(jī)名檢查就不能將其設(shè)置回 CERT_NONEPROTOCOL_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_modeCERT_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_CLIENTPROTOCOL_TLS_SERVER 以外的其他協(xié)議來說都是只讀的。

maximum_version, minimum_versionSSLContext.options 等屬性都會(huì)影響上下文所支持的 SSL 和 TLS 版本。 這個(gè)實(shí)現(xiàn)不會(huì)阻止無效的組合。 例如一個(gè) optionsOP_NO_TLSv1_2maximum_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_OPTIONALCERT_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_OPTIONALCERT_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_REQUIREDcheck_hostname 設(shè)為 True。 所有其他協(xié)議都會(huì)使用不安全的默認(rèn)值創(chuàng)建 SSL 上下文。

當(dāng)你使用此上下文去連接服務(wù)器時(shí),CERT_REQUIREDcheck_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ā) SSLWantWriteErrorSSLWantReadError 而非 BlockingIOError。 如果有必要在下層套接字上執(zhí)行讀取操作將引發(fā) SSLWantReadError,在下層套接字上執(zhí)行寫入操作則將引發(fā) SSLWantWriteError。 請(qǐng)注意嘗試 寫入 到 SSL 套接字可能需要先從下層套接字 讀取,而嘗試從 SSL 套接字 讀取 則可能需要先向下層套接字 寫入。

    在 3.5 版更改: 在較早的 Python 版本中,SSLSocket.send() 方法會(huì)返回零值而非引發(fā) SSLWantWriteErrorSSLWantReadError。

  • 調(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, SSLWantReadErrorBlockingIOError 等異常。 它還會(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 用法的一些說明:

在 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 的長度相等。

write_eof()?

將一個(gè) EOF 標(biāo)記寫入到內(nèi)存 BIO。 在此方法被調(diào)用以后,再調(diào)用 write() 將是非法的。 屬性 eof will 在緩沖區(qū)當(dāng)前的所有數(shù)據(jù)都被讀取之后將變?yōu)檎嬷怠?/p>

SSL 會(huì)話?

3.6 新版功能.

class ssl.SSLSession?

session 所使用的會(huì)話對(duì)象。

id?
time?
timeout?
ticket_lifetime_hint?
has_ticket?

安全考量?

最佳默認(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_CLIENTPROTOCOL_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)用的一部分(例如使用 multiprocessingconcurrent.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.sessionSSLSession 與 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í)某些特性將不可用。