ssl --- 套接字對象的 TLS/SSL 包裝器?

源代碼: Lib/ssl.py


This module provides access to Transport Layer Security (often known as "Secure Sockets Layer") encryption and peer authentication facilities for network sockets, both client-side and server-side. This module uses the OpenSSL library. It is available on all modern Unix systems, Windows, macOS, and probably additional platforms, as long as OpenSSL is installed on that platform.

備注

某些行為可能與平臺相關(guān),因為調用了操作系統的套接字 API。已安裝的OpenSSL 版本也可能會(huì )導致不同的行為。比如 TLSv 1.3 與 Open SSL 1.1.1 就不一樣。

警告

在閱讀 安全考量 前不要使用此模塊。 這樣做可能會(huì )導致虛假的安全感,因為ssl模塊的默認設置不一定適合你的應用程序。

文檔本文檔記錄``ssl`` 模塊的對象和函數;更多關(guān)于TLS,SSL,和證書(shū)的信息,請參閱下方的“詳情”選項

本模塊提供了一個(gè)類(lèi) ssl.SSLSocket,它派生自 socket.socket 類(lèi)型,并提供類(lèi)似套接字的包裝器,也能夠對通過(guò)帶 SSL 套接字的數據進(jìn)行加密和解密。 它支持一些額外方法例如 getpeercert(),該方法可從連接的另一端獲取證書(shū),還有 cipher(),該方法可獲取安全連接所使用的密碼。

對于更復雜的應用程序,ssl.SSLContext 類(lèi)有助于管理設置項和證書(shū),進(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 已過(guò)時(shí),將不再被支持。在 ssl 模塊未來(lái)的版本中,最低需要 OpenSSL 1.0.2 或 1.1.0。

在 3.10 版更改: PEP 644 已經(jīng)實(shí)現。ssl 模塊需要 OpenSSL 1.1.1 以上版本的支持。

使用廢棄的常量和函數會(huì )導致廢棄警告。

方法、常量和異常處理?

套接字創(chuàng )建?

從 Python 3.2 和 2.7.9 開(kāi)始,建議使用 SSLContext 實(shí)例的 SSLContext.wrap_socket() 來(lái)將套接字包裝為 SSLSocket 對象。 輔助函數 create_default_context() 會(huì )返回一個(gè)新的帶有安全默認設置的上下文。 舊的 wrap_socket() 函數已被棄用,因為它效率較差并且不支持服務(wù)器名稱(chēng)提示(SNI)和主機匹配。

客戶(hù)端套接字實(shí)例,采用默認上下文和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())

客戶(hù)端套接字示例,帶有自定義上下文和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上監聽(tīng)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 )建?

便捷函數,可以幫助創(chuàng )建 SSLContext 對象,用于常見(jiàn)的目的。

ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)?

返回一個(gè)新的 SSLContext 對象,使用給定 purpose 的默認設置。 該設置由 ssl 模塊選擇,并且通常是代表一個(gè)比直接調用 SSLContext 構造器時(shí)更高的安全等級。

cafile, capath, cadata 代表用于進(jìn)行證書(shū)核驗的可選受信任 CA 證書(shū),與 SSLContext.load_verify_locations() 的一致。 如果三個(gè)參數均為 None,此函數可以轉而選擇信任系統的默認 CA 證書(shū)。

設置為: PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER、 OP_NO_SSLv2OP_NO_SSLv3,帶有不含 RC4 及未認證的高強度加密密碼套件。 傳入 SERVER_AUTH 作為 purpose,會(huì )將 verify_mode 設為 CERT_REQUIRED,并加載 CA 證書(shū)(若給出 cafile、capathcadata 之一)或用 SSLContext.load_default_certs() 加載默認CA證書(shū)。

keylog_filename 受支持并且設置了環(huán)境變量 SSLKEYLOGFILE 時(shí),create_default_context() 會(huì )啟用密鑰日志記錄。

備注

協(xié)議、選項、密碼和其他設置可隨時(shí)更改為更具約束性的值而無(wú)須事先棄用。 這些值代表了兼容性和安全性之間的合理平衡。

如果你的應用需要特定的設置,你應當創(chuàng )建一個(gè) SSLContext 并自行應用設置。

備注

如果你發(fā)現當某些較舊的客戶(hù)端或服務(wù)器嘗試與用此函數創(chuàng )建的 SSLContext 進(jìn)行連接時(shí)收到了報錯提示 "Protocol or cipher suite mismatch",這可能是因為它們只支持 SSL3.0 而它被此函數用 OP_NO_SSLv3 排除掉了。 SSL3.0 被廣泛認為 完全不可用。 如果你仍希望繼續使用此函數但仍允許 SSL 3.0 連接,你可以使用以下代碼重新啟用它們:

ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
ctx.options &= ~ssl.OP_NO_SSLv3

3.4 新版功能.

在 3.4.4 版更改: RC4 被從默認密碼字符串中丟棄。

在 3.6 版更改: ChaCha20/Poly1305 被添加到默認密碼字符串中。

3DES 被從默認密碼字符串中丟棄。

在 3.8 版更改: 增加了對密鑰日志記錄至 SSLKEYLOGFILE 的支持。

在 3.10 版更改: 當前上下文使用 PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER 協(xié)議而非通用的 PROTOCOL_TLS。

異常?

exception ssl.SSLError?

引發(fā)此異常以提示來(lái)自下層 SSL 實(shí)現(目前由 OpenSSL 庫提供)的錯誤。 它表示在下層網(wǎng)絡(luò )連接之上疊加的高層級加密和驗證層存在某種問(wèn)題。 此錯誤是 OSError 的一個(gè)子類(lèi)型。 SSLError 實(shí)例的錯誤和消息是由 OpenSSL 庫提供的。

在 3.3 版更改: SSLError 曾經(jīng)是 socket.error 的一個(gè)子類(lèi)型。

library?

一個(gè)字符串形式的助記符,用來(lái)指明發(fā)生錯誤的 OpenSSL 子模塊,例如 SSL, PEMX509。 可能的取值范圍依賴(lài)于 OpenSSL 的版本。

3.3 新版功能.

reason?

一個(gè)字符串形式的助記符,用來(lái)指明發(fā)生錯誤的原因,例如 CERTIFICATE_VERIFY_FAILED。 可能的取值范圍依賴(lài)于 OpenSSL 的版本。

3.3 新版功能.

exception ssl.SSLZeroReturnError?

SSLError 的子類(lèi),當嘗試讀取或寫(xiě)入且 SSL 連接已被完全關(guān)閉時(shí)會(huì )被引發(fā)。 請注意這并不意味著(zhù)下層的傳輸(讀取 TCP)已被關(guān)閉。

3.3 新版功能.

exception ssl.SSLWantReadError?

SSLError 的子類(lèi),當嘗試讀取或寫(xiě)入數據,但在請求被滿(mǎn)足之前還需要在下層的 TCP 傳輸上接收更多數據時(shí)會(huì )被 非阻塞型 SSL 套接字 引發(fā)。

3.3 新版功能.

exception ssl.SSLWantWriteError?

SSLError 的子類(lèi),當嘗試讀取或寫(xiě)入數據,但在請求被滿(mǎn)足之前還需要在下層的 TCP 傳輸上發(fā)送更多數據時(shí)會(huì )被 非阻塞型 SSL 套接字 引發(fā)。

3.3 新版功能.

exception ssl.SSLSyscallError?

SSLError 的子類(lèi),當嘗試在 SSL 套接字上執行操作時(shí)遇到系統錯誤時(shí)會(huì )被引發(fā)。 不幸的是,沒(méi)有簡(jiǎn)單的方式能檢查原始 errno 編號。

3.3 新版功能.

exception ssl.SSLEOFError?

SSLError 的子類(lèi),當 SSL 連接被突然終止時(shí)會(huì )被引發(fā)。 通常,當遇到此錯誤時(shí)你不應再?lài)L試重用下層的傳輸。

3.3 新版功能.

exception ssl.SSLCertVerificationError?

SSLError 的子類(lèi),當證書(shū)驗證失敗時(shí)會(huì )被引發(fā)。

3.7 新版功能.

verify_code?

一個(gè)數字形式的錯誤編號,用于表示驗證錯誤。

verify_message?

用于表示驗證錯誤的人類(lèi)可讀的字符串。

exception ssl.CertificateError?

SSLCertVerificationError 的別名。

在 3.7 版更改: 此異?,F在是 SSLCertVerificationError 的別名。

隨機生成?

ssl.RAND_bytes(num)?

返回 num 個(gè)高加密強度偽隨機字節數據。 如果 PRNG 未使用足夠的數據作為隨機種子或者如果當前 RAND 方法不支持該操作則會(huì )引發(fā) SSLError。 RAND_status() 可被用來(lái)檢查 PRNG 的狀態(tài)而 RAND_add() 可被用來(lái)為 PRNG 設置隨機種子。

對于幾乎所有應用程序都更推薦使用 os.urandom()。

請閱讀維基百科文章 Cryptographically secure pseudorandom number generator (CSPRNG) 以了解對于高加密強度生成器的具體要求。

3.3 新版功能.

ssl.RAND_pseudo_bytes(num)?

返回 (bytes, is_cryptographic): bytes 是 num 個(gè)偽隨機字節數據,如果所生成的字節數據為高加密強度則 is_cryptographic 為 True。 如果當前 RAND 方法不支持此操作則會(huì )引發(fā) SSLError。

所生成的偽隨機字節序列如果具有足夠的長(cháng)度則將會(huì )具有唯一性,并是并非不可預測。 它們可被用于非加密目的以及加密協(xié)議中的特定目的,但通常不可被用于密鑰生成等目的。

對于幾乎所有應用程序都更推薦使用 os.urandom()。

3.3 新版功能.

3.6 版后已移除: OpenSSL 已棄用了 ssl.RAND_pseudo_bytes(),請改用 ssl.RAND_bytes()。

ssl.RAND_status()?

如果 SSL 偽隨機數生成器已使用‘足夠的’隨機性作為種子則返回 True,否則返回 False。 你可以使用 ssl.RAND_egd()ssl.RAND_add() 來(lái)增加偽隨機數生成器的隨機性。

ssl.RAND_add(bytes, entropy)?

將給定的 bytes 混合到 SSL 偽隨機數生成器中。 形參 entropy (float 類(lèi)型) 是數據所包含的熵的下界 (因此你可以總是使用 0.0)。 請查看 RFC 1750 了解有關(guān)熵源的更多信息。

在 3.5 版更改: 現在接受可寫(xiě)的 字節類(lèi)對象。

證書(shū)處理?

ssl.match_hostname(cert, hostname)?

驗證 cert (使用 SSLSocket.getpeercert() 所返回的已解碼格式) 是否匹配給定的 hostname。 所應用的規則是在 RFC 2818, RFC 5280RFC 6125 中描述的檢查 HTTPS 服務(wù)器身份的規則。 除了 HTTPS,此函數還應當適用于各種基于 SSL 協(xié)議的服務(wù)器身份檢查操作,例如 FTPS, IMAPS, POPS 等等。

失敗時(shí)引發(fā) CertificateError。 成功時(shí)此函數無(wú)返回值:

>>>
>>> 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 版更改: 此函數現在遵循 RFC 6125, 6.4.3 小節,它不會(huì )匹配多個(gè)通配符 (例如 *.*.com*a*.example.org) 也不匹配國際化域名 (IDN) 片段內部的通配符。 IDN A 標簽例如 www*.xn--pthon-kva.org 仍然受支持,但 x*.python.org 不再能匹配 xn--tda.python.org。

在 3.5 版更改: 現在支持匹配存在于證書(shū)的 subjectAltName 字段中的 IP 地址。

在 3.7 版更改: 此函數不再被用于 TLS 連接。 主機匹配現在是由 OpenSSL 執行的。

允許位于段的最左端且為唯一字符的通配符。 部分通配符例如 www*.example.com 已不再受支持。

3.7 版后已移除.

ssl.cert_time_to_seconds(cert_time)?

返回距離 Unix 紀元零時(shí)的秒數,給定的 cert_time 字符串代表來(lái)自證書(shū)的 "notBefore" 或 "notAfter" 日期值,采用 "%b %d %H:%M:%S %Y %Z" strptime 格式(C 區域)。

以下為示例代碼:

>>>
>>> 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í)區。 在之前使用的是本地時(shí)區。 返回一個(gè)整數(不帶輸入格式中秒的分數部分)

ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS_CLIENT, ca_certs=None[, timeout])?

給出一個(gè)受 SSL 保護的服務(wù)器的地址 addr,形式為 (hostname, port-number) ,獲取該服務(wù)器的證書(shū),并以 PEM 編碼的字符串返回。如果指定了 ssl_version,則使用該版本的 SSL 協(xié)議嘗試連接服務(wù)器。如果指定了 ca_certs,它應該是一個(gè)包含根證書(shū)列表的文件,與 SSLContext.wrap_socket() 中同名參數的格式相同。該調用將嘗試根據該根證書(shū)集來(lái)驗證服務(wù)器的證書(shū),如果驗證失敗則調用失敗。參數 timeout 可用于指定超時(shí)時(shí)間。

在 3.3 版更改: 此函數現在是 IPv6 兼容的。-compatible.

在 3.5 版更改: 默認的 ssl_versionPROTOCOL_SSLv3 改為 PROTOCOL_TLS 以保證與現代服務(wù)器的最大兼容性。

在 3.10 版更改: 加入 timeout 參數。

ssl.DER_cert_to_PEM_cert(DER_cert_bytes)?

根據給定的 DER 編碼字節塊形式的證書(shū),返回同一證書(shū)的 PEM 編碼字符串版本。

ssl.PEM_cert_to_DER_cert(PEM_cert_string)?

根據給定的 ASCII PEM 字符串形式的證書(shū),返回同一證書(shū)的 DER 編碼字節序列。

ssl.get_default_verify_paths()?

返回包含 OpenSSL 的默認 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 的系統證書(shū)庫中檢索證書(shū)。 store_name 可以是 CA, ROOTMY 中的一個(gè)。 Windows 也可能會(huì )提供額外的證書(shū)庫。

此函數返回一個(gè)包含 (cert_bytes, encoding_type, trust) 元組的列表。 encoding_type 指明 cert_bytes 的編碼格式。 它可以為 x509_asn 以表示 X.509 ASN.1 數據或是 pkcs_7_asn 以表示 PKCS#7 ASN.1 數據。 trust 以 OIDS 集合的形式指明證書(shū)的目的,或者如果證書(shū)對于所有目的都可以信任則為 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 的系統證書(shū)庫中檢索 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 數據或是 pkcs_7_asn 以表示 PKCS#7 ASN.1 數據。

可用性: 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í)例,該類(lèi)型是 socket.socket 的子類(lèi)型,它將下層的套接字包裝在一個(gè) SSL 上下文中。 sock 必須是一個(gè) SOCK_STREAM 套接字;其他套接字類(lèi)型不被支持。

在內部,該函數會(huì )創(chuàng )建一個(gè) SSLContext,其協(xié)議版本為 ssl_versionSSLContext.options 設為 cert_reqs。 如果設置了 keyfile, certfile, ca_certsciphers 等形參,則參數值會(huì )被傳給 SSLContext.load_cert_chain(), SSLContext.load_verify_locations() 以及 SSLContext.set_ciphers()。

參數 server_side, do_handshake_on_connectsuppress_ragged_eofs 具有與 SSLContext.wrap_socket() 相同的含義。

3.7 版后已移除: 從 Python 3.2 和 2.7.9 開(kāi)始,建議使用 SSLContext.wrap_socket() 來(lái)代替 wrap_socket()。 模塊級函數的功能受限并且將創(chuàng )建不安全的客戶(hù)端套接字,不帶服務(wù)器名稱(chēng)提示或主機名匹配。

常量?

所有常量現在都是 enum.IntEnumenum.IntFlag 多項集的成員。

3.6 新版功能.

ssl.CERT_NONE?

SSLContext.verify_modewrap_socket()cert_reqs 形參可能的取值。 PROTOCOL_TLS_CLIENT 除外,這是默認的模式。 對于客戶(hù)端套接字,幾乎任何證書(shū)都是可接受的。 驗證錯誤例如不受信任或過(guò)期的證書(shū)錯誤會(huì )被忽略并且不會(huì )中止 TLS/SSL 握手。

在服務(wù)器模式下,不會(huì )從客戶(hù)端請求任何證書(shū),因此客戶(hù)端不會(huì )發(fā)送任何用于客戶(hù)端證書(shū)身份驗證的證書(shū)。

參見(jiàn)下文對于 安全考量 的討論。

ssl.CERT_OPTIONAL?

SSLContext.verify_modewrap_socket()cert_reqs 形參可能的取值。 CERT_OPTIONAL 具有與 CERT_REQUIRED 相同的含義。 對于客戶(hù)端套接字推薦改用 CERT_REQUIRED。

在服務(wù)器模式下,客戶(hù)端證書(shū)請求會(huì )被發(fā)送給客戶(hù)端。 客戶(hù)端可以忽略請求也可以發(fā)送一個(gè)證書(shū)以執行 TLS 客戶(hù)端證書(shū)身份驗證。 如果客戶(hù)端選擇發(fā)送證書(shū),則將對其執行驗證。 任何驗證錯誤都將立即中止 TLS 握手。

使用此設置要求將一組有效的 CA 證書(shū)傳遞給 SSLContext.load_verify_locations() 或是作為 wrap_socket()ca_certs 形參值。

ssl.CERT_REQUIRED?

SSLContext.verify_modewrap_socket()cert_reqs 形參可能的取值。 在此模式下,需要從套接字連接的另一端獲取證書(shū);如果未提供證書(shū)或驗證失敗則將引發(fā) SSLError。 此模式 不能 在客戶(hù)端模式下對證書(shū)進(jìn)行驗證,因為它不會(huì )匹配主機名。 check_hostname 也必須被啟用以驗證證書(shū)的真實(shí)性。 PROTOCOL_TLS_CLIENT 會(huì )使用 CERT_REQUIRED 并默認啟用 check_hostname。

對于服務(wù)器套接字,此模式會(huì )提供強制性的 TLS 客戶(hù)端證書(shū)驗證。 客戶(hù)端證書(shū)請求會(huì )被發(fā)送給客戶(hù)端并且客戶(hù)端必須提供有效且受信任的證書(shū)。

使用此設置要求將一組有效的 CA 證書(shū)傳遞給 SSLContext.load_verify_locations() 或是作為 wrap_socket()ca_certs 形參值。

class ssl.VerifyMode?

CERT_* 常量的 enum.IntEnum 多項集。

3.6 新版功能.

ssl.VERIFY_DEFAULT?

SSLContext.verify_flags 可能的取值。 在此模式下,證書(shū)吊銷(xiāo)列表(CRL)并不會(huì )被檢查。 OpenSSL 默認不要求也不驗證 CRL。

3.4 新版功能.

ssl.VERIFY_CRL_CHECK_LEAF?

SSLContext.verify_flags 可能的取值。 在此模式下, 只會(huì )檢查對等證書(shū)而不檢查任何中間 CA 證書(shū)。 此模式要求提供由對等證書(shū)頒發(fā)者(其直接上級 CA)簽名的有效 CRL。 如果未使用 SSLContext.load_verify_locations 加載正確的 CRL,則驗證將失敗。

3.4 新版功能.

ssl.VERIFY_CRL_CHECK_CHAIN?

SSLContext.verify_flags 可能的取值。 在此模式下,會(huì )檢查對等證書(shū)鏈中所有證書(shū)的 CRL。

3.4 新版功能.

ssl.VERIFY_X509_STRICT?

SSLContext.verify_flags 可能的取值,用于禁用已損壞 X.509 證書(shū)的繞過(guò)操作。

3.4 新版功能.

ssl.VERIFY_ALLOW_PROXY_CERTS?

SSLContext.verify_flags 的可能取值,啟用代理證書(shū)驗證。

3.10 新版功能.

ssl.VERIFY_X509_TRUSTED_FIRST?

SSLContext.verify_flags 可能的取值。 它指示 OpenSSL 在構建用于驗證某個(gè)證書(shū)的信任鏈時(shí)首選受信任的證書(shū)。 此旗標將默認被啟用。

3.4.4 新版功能.

ssl.VERIFY_X509_PARTIAL_CHAIN?

SSLContext.verify_flags 的可能取值。它指示 OpenSSL 接受信任存儲中的中間 CA 作為信任錨,與自我簽名的根 CA 證書(shū)的方式相同。這樣就能信任中間 CA 頒發(fā)的證書(shū),而不一定非要去信任其祖先的根 CA。

3.10 新版功能.

class ssl.VerifyFlags?

VERIFY_* 常量的 enum.IntFlag 多項集。

3.6 新版功能.

ssl.PROTOCOL_TLS?

選擇客戶(hù)端和服務(wù)器均支持的最高協(xié)議版本。 此選項名稱(chēng)并不準確,實(shí)際上 "SSL" 和 "TLS" 協(xié)議均可被選擇。

3.6 新版功能.

3.10 版后已移除: TLS 客戶(hù)端和服務(wù)器需要不同的默認設置來(lái)實(shí)現安全通信。通用的 TLS 協(xié)議常量已廢棄,而采用 PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER。

ssl.PROTOCOL_TLS_CLIENT?

自動(dòng)協(xié)商為客戶(hù)端和服務(wù)器都支持的最高版本協(xié)議,并配置當前上下文客戶(hù)端的連接。該協(xié)議默認啟用 CERT_REQUIREDcheck_hostname。

3.6 新版功能.

ssl.PROTOCOL_TLS_SERVER?

自動(dòng)協(xié)商為客戶(hù)端和服務(wù)器都支持的最高版本協(xié)議,并配置上下文服務(wù)器端的連接。

3.6 新版功能.

ssl.PROTOCOL_SSLv23?

PROTOCOL_TLS 的別名。

3.6 版后已移除: 請改用 PROTOCOL_TLS。

ssl.PROTOCOL_SSLv2?

選擇 SSL 版本 2 作為通道加密協(xié)議。

This protocol is not available if OpenSSL is compiled with the no-ssl2 option.

警告

SSL 版本 2 并不安全。 極不建議使用它。

3.6 版后已移除: OpenSSL 已經(jīng)移除了對 SSLv2 的支持。

ssl.PROTOCOL_SSLv3?

選擇 SSL 版本 3 作為通道加密協(xié)議。

This protocol is not available if OpenSSL is compiled with the no-ssl3 option.

警告

SSL 版本 3 并不安全。 極不建議使用它。

3.6 版后已移除: OpenSSL 已經(jīng)廢棄了所有特定于版本的協(xié)議。請換用帶有 SSLContext.minimum_versionSSLContext.maximum_version 的默認協(xié)議 PROTOCOL_TLS_SERVERPROTOCOL_TLS_CLIENT 。

ssl.PROTOCOL_TLSv1?

選擇 TLS 版本 1.0 作為通道加密協(xié)議。

3.6 版后已移除: OpenSSL 已經(jīng)廢棄了所有特定于版本的協(xié)議。

ssl.PROTOCOL_TLSv1_1?

選擇 TLS 版本 1.1 作為通道加密協(xié)議。 僅適用于 openssl 版本 1.0.1+。

3.4 新版功能.

3.6 版后已移除: OpenSSL 已經(jīng)廢棄了所有特定于版本的協(xié)議。

ssl.PROTOCOL_TLSv1_2?

選用 TLS 1.2 版本作為隧道加密協(xié)議。只適用于 openssl 1.0.1 以上版本。

3.4 新版功能.

3.6 版后已移除: OpenSSL 已經(jīng)廢棄了所有特定于版本的協(xié)議。

ssl.OP_ALL?

對存在于其他 SSL 實(shí)現中的各種缺陷啟用繞過(guò)操作。 默認會(huì )設置此選項。 沒(méi)有必要設置與 OpenSSL 的 SSL_OP_ALL 常量同名的旗標。

3.2 新版功能.

ssl.OP_NO_SSLv2?

阻止 SSLv2 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 SSLv2 作為協(xié)議版本。

3.2 新版功能.

3.6 版后已移除: SSLv2 已被棄用

ssl.OP_NO_SSLv3?

阻止 SSLv3 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 SSLv3 作為協(xié)議版本。

3.2 新版功能.

3.6 版后已移除: SSLv3 已被棄用

ssl.OP_NO_TLSv1?

阻止 TLSv1 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 TLSv1 作為協(xié)議版本。

3.2 新版功能.

3.7 版后已移除: 此選項自 OpenSSL 1.1.0 起已被棄用,請改用新的 SSLContext.minimum_versionSSLContext.maximum_version。

ssl.OP_NO_TLSv1_1?

阻止 TLSv1.1 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 TLSv1.1 作為協(xié)議版本。 僅適用于 openssl 版本 1.0.1+。

3.4 新版功能.

3.7 版后已移除: 此選項自 OpenSSL 1.1.0 起已被棄用。

ssl.OP_NO_TLSv1_2?

阻止 TLSv1.2 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 TLSv1.2 作為協(xié)議版本。 僅適用于 openssl 版本 1.0.1+。

3.4 新版功能.

3.7 版后已移除: 此選項自 OpenSSL 1.1.0 起已被棄用。

ssl.OP_NO_TLSv1_3?

阻止 TLSv1.3 連接。 此選項僅可與 PROTOCOL_TLS 結合使用。 它會(huì )阻止對等方選擇 TLSv1.3 作為協(xié)議版本。 TLS 1.3 適用于 OpenSSL 1.1.1 或更新的版本。 當 Python 編譯是基于較舊版本的 OpenSSL 時(shí),該旗標默認為 0。

3.7 新版功能.

3.7 版后已移除: 此選項自 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 消息,并忽略通過(guò) ClientHello 發(fā)起的重協(xié)商請求。

此選項僅適用于 OpenSSL 1.1.0h 及更新的版本。

3.7 新版功能.

ssl.OP_CIPHER_SERVER_PREFERENCE?

使用服務(wù)器的密碼順序首選項,而不是客戶(hù)端的首選項。 此選項在客戶(hù)端套接字和 SSLv2 服務(wù)器套接字上無(wú)效。

3.3 新版功能.

ssl.OP_SINGLE_DH_USE?

阻止對于單獨的 SSL 會(huì )話(huà)重用相同的 DH 密鑰。 這會(huì )提升前向保密性但需要更多的計算資源。 此選項僅適用于服務(wù)器套接字。

3.3 新版功能.

ssl.OP_SINGLE_ECDH_USE?

阻止對于單獨的 SSL 會(huì )話(huà)重用相同的 ECDH 密鑰。 這會(huì )提升前向保密性但需要更多的計算資源。 此選項僅適用于服務(wù)器套接字。

3.3 新版功能.

ssl.OP_ENABLE_MIDDLEBOX_COMPAT?

在 TLS 1.3 握手中發(fā)送虛擬更改密碼規格(CCS)消息以使得 TLS 1.3 連接看起來(lái)更像是 TLS 1.2 連接。

此選項僅適用于 OpenSSL 1.1.1 及更新的版本。

3.8 新版功能.

ssl.OP_NO_COMPRESSION?

在 SSL 通道上禁用壓縮。 這適用于應用協(xié)議支持自己的壓縮方案的情況。

3.3 新版功能.

class ssl.Options?

OP_* 常量的 enum.IntFlag 多項集。

ssl.OP_NO_TICKET?

阻止客戶(hù)端請求會(huì )話(huà)憑據。

3.6 新版功能.

ssl.OP_IGNORE_UNEXPECTED_EOF?

忽略 TLS 連接的意外關(guān)閉。

此選項僅適用于 OpenSSL 3.0.0 及更新的版本。

3.10 新版功能.

ssl.HAS_ALPN?

OpenSSL 庫是否具有對 RFC 7301 中描述的 應用層協(xié)議協(xié)商 TLS 擴展的內置支持。

3.5 新版功能.

ssl.HAS_NEVER_CHECK_COMMON_NAME?

OpenSSL 庫是否具有對不檢測目標通用名稱(chēng)的內置支持且 SSLContext.hostname_checks_common_name 為可寫(xiě)狀態(tài)。

3.7 新版功能.

ssl.HAS_ECDH?

OpenSSL 庫是否具有對基于橢圓曲線(xiàn)的 Diffie-Hellman 密鑰交換的內置支持。 此常量應當為真值,除非發(fā)布者明確地禁用了此功能。

3.3 新版功能.

ssl.HAS_SNI?

OpenSSL 庫是否具有對 服務(wù)器名稱(chēng)提示 擴展(在 RFC 6066 中定義)的內置支持。

3.2 新版功能.

ssl.HAS_NPN?

OpenSSL 庫是否具有對 應用層協(xié)議協(xié)商 中描述的 下一協(xié)議協(xié)商 的內置支持。 當此常量為真值時(shí),你可以使用 SSLContext.set_npn_protocols() 方法來(lái)公告你想要支持的協(xié)議。

3.3 新版功能.

ssl.HAS_SSLv2?

OpenSSL 庫是否具有對 SSL 2.0 協(xié)議的內置支持。

3.7 新版功能.

ssl.HAS_SSLv3?

OpenSSL 庫是否具有對 SSL 3.0 協(xié)議的內置支持。

3.7 新版功能.

ssl.HAS_TLSv1?

OpenSSL 庫是否具有對 TLS 1.0 協(xié)議的內置支持。

3.7 新版功能.

ssl.HAS_TLSv1_1?

OpenSSL 庫是否具有對 TLS 1.1 協(xié)議的內置支持。

3.7 新版功能.

ssl.HAS_TLSv1_2?

OpenSSL 庫是否具有對 TLS 1.2 協(xié)議的內置支持。

3.7 新版功能.

ssl.HAS_TLSv1_3?

OpenSSL 庫是否具有對 TLS 1.3 協(xié)議的內置支持。

3.7 新版功能.

ssl.CHANNEL_BINDING_TYPES?

受支持的 TLS 通道綁定類(lèi)型組成的列表。 此列表中的字符串可被用作傳給 SSLSocket.get_channel_binding() 的參數。

3.3 新版功能.

ssl.OPENSSL_VERSION?

解釋器所加載的 OpenSSL 庫的版本字符串:

>>>
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.0.2k  26 Jan 2017'

3.2 新版功能.

ssl.OPENSSL_VERSION_INFO?

代表 OpenSSL 庫的版本信息的五個(gè)整數所組成的元組:

>>>
>>> ssl.OPENSSL_VERSION_INFO
(1, 0, 2, 11, 15)

3.2 新版功能.

ssl.OPENSSL_VERSION_NUMBER?

OpenSSL 庫的原始版本號,以單個(gè)整數表示:

>>>
>>> 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_*

來(lái)自 RFC 5246 等文檔的警報描述。 IANA TLS Alert Registry 中包含了這個(gè)列表及對定義其含義的 RFC 引用。

被用作 SSLContext.set_servername_callback() 中的回調函數的返回值。

3.4 新版功能.

class ssl.AlertDescription?

ALERT_DESCRIPTION_* 常量的 enum.IntEnum 多項集。

3.6 新版功能.

Purpose.SERVER_AUTH?

用于 create_default_context()SSLContext.load_default_certs() 的參數。表示上下文可用于驗證網(wǎng)絡(luò )服務(wù)器(因此,它將被用于創(chuàng )建客戶(hù)端套接字)。

3.4 新版功能.

Purpose.CLIENT_AUTH?

用于 create_default_context()SSLContext.load_default_certs() 的參數。 表示上下文可用于驗證網(wǎng)絡(luò )客戶(hù)(因此,它將被用于創(chuàng )建服務(wù)器端套接字)。

3.4 新版功能.

class ssl.SSLErrorNumber?

SSL_ERROR_* 常量的 enum.IntEnum 多項集。

3.6 新版功能.

class ssl.TLSVersion?

SSLContext.maximum_versionSSLContext.minimum_version 中的 SSL 和 TLS 版本的 enum.IntEnum 多項集。

3.7 新版功能.

TLSVersion.MINIMUM_SUPPORTED?
TLSVersion.MAXIMUM_SUPPORTED?

受支持的最低和最高 SSL 或 TLS 版本。 這些常量被稱(chēng)為魔術(shù)常量。 它們的值并不反映可用的最低和最高 TLS/SSL 版本。

TLSVersion.SSLv3?
TLSVersion.TLSv1?
TLSVersion.TLSv1_1?
TLSVersion.TLSv1_2?
TLSVersion.TLSv1_3?

SSL 3.0 至 TLS 1.3。

3.10 版后已移除: 所有 TLSVersion 成員,除 TLSVersion.TLSv1_2TLSVersion.TLSv1_3 之外均已廢棄。

SSL 套接字?

class ssl.SSLSocket(socket.socket)?

SSL 套接字提供了 套接字對象 的下列方法:

但是,由于 SSL(和 TLS)協(xié)議在 TCP 之上具有自己的框架,因此 SSL 套接字抽象在某些方面可能與常規的 OS 層級套接字存在差異。 特別是要查看 非阻塞型套接字說(shuō)明。

SSLSocket 的實(shí)例必須使用 SSLContext.wrap_socket() 方法來(lái)創(chuàng )建。

在 3.5 版更改: 新增了 sendfile() 方法。

在 3.5 版更改: shutdown() 不會(huì )在每次接收或發(fā)送字節數據后重置套接字超時(shí)。 現在套接字超時(shí)為關(guān)閉的最大總持續時(shí)間。

3.6 版后已移除: 直接創(chuàng )建 SSLSocket 實(shí)例的做法已被棄用,請使用 SSLContext.wrap_socket() 來(lái)包裝套接字。

在 3.7 版更改: SSLSocket 的實(shí)例必須使用 wrap_socket() 來(lái)創(chuàng )建。 在較早的版本中,直接創(chuàng )建實(shí)例是可能的。 但這從未被記入文檔或是被正式支持。

在 3.10 版更改: Python 內部現在使用 SSL_read_exSSL_write_ex。這些函數支持讀取和寫(xiě)入大于 2GB 的數據。寫(xiě)入零長(cháng)數據不再出現違反協(xié)議的錯誤。

SSL 套接字還具有下列方法和屬性:

SSLSocket.read(len=1024, buffer=None)?

從 SSL 套接字讀取至多 len 個(gè)字節的數據并將結果作為 bytes 實(shí)例返回。 如果指定了 buffer,則改為讀取到緩沖區,并返回所讀取的字節數。

如果套接字為 非阻塞型 則會(huì )引發(fā) SSLWantReadErrorSSLWantWriteError 且讀取將阻塞。

由于在任何時(shí)候重新協(xié)商都是可能的,因此調用 read() 也可能導致寫(xiě)入操作。

在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節數據后不會(huì )再被重置。 現在套接字超時(shí)為讀取至多 len 個(gè)字節數據的最大總持續時(shí)間。

3.6 版后已移除: 請使用 recv() 來(lái)代替 read()。

SSLSocket.write(buf)?

buf 寫(xiě)入到 SSL 套接字并返回所寫(xiě)入的字節數。 buf 參數必須為支持緩沖區接口的對象。

如果套接字為 非阻塞型 則會(huì )引發(fā) SSLWantReadErrorSSLWantWriteError 且讀取將阻塞。

由于在任何時(shí)候重新協(xié)商都是可能的,因此調用 write() 也可能導致讀取操作。

在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節數據后不會(huì )再被重置。 現在套接字超時(shí)為寫(xiě)入 buf 的最大總持續時(shí)間。

3.6 版后已移除: 請使用 send() 來(lái)代替 write()。

備注

read()write() 方法是讀寫(xiě)未加密的應用級數據,并將其解密/加密為帶加密的線(xiàn)路級數據的低層級方法。 這些方法需要有激活的 SSL 連接,即握手已完成而 SSLSocket.unwrap() 尚未被調用。

通常你應當使用套接字 API 方法例如 recv()send() 來(lái)代替這些方法。

SSLSocket.do_handshake()?

執行 SSL 設置握手。

在 3.4 版更改: 當套接字的 contextcheck_hostname 屬性為真值時(shí)此握手方法還會(huì )執行 match_hostname()。

在 3.5 版更改: 套接字超時(shí)在每次接收或發(fā)送字節數據時(shí)不會(huì )再被重置。 現在套接字超時(shí)為握手的最大總持續時(shí)間。

在 3.7 版更改: 主機名或 IP 地址會(huì )在握手期間由 OpenSSL 進(jìn)行匹配。 函數 match_hostname() 將不再被使用。 在 OpenSSL 拒絕主機名和 IP 地址的情況下,握手將提前被中止并向對等方發(fā)送 TLS 警告消息。

SSLSocket.getpeercert(binary_form=False)?

如果連接另一端的對等方?jīng)]有證書(shū),則返回 None。 如果 SSL 握手還未完成,則會(huì )引發(fā) ValueError。

如果 binary_form 形參為 False,并且從對等方接收到了證書(shū),此方法將返回一個(gè) dict 實(shí)例。 如果證書(shū)未通過(guò)驗證,則字典將為空。 如果證書(shū)通過(guò)驗證,它將返回由多個(gè)密鑰組成的字典,其中包括 subject (證書(shū)頒發(fā)給的主體) 和 issuer (頒發(fā)證書(shū)的主體)。 如果證書(shū)包含一個(gè) Subject Alternative Name 擴展的實(shí)例 (see RFC 3280),則字典中還將有一個(gè) subjectAltName 鍵。

subjectissuer 字段都是包含在證書(shū)中相應字段的數據結構中給出的相對專(zhuān)有名稱(chēng)(RDN)序列的元組,每個(gè) RDN 均為 name-value 對的序列。 這里是一個(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}

備注

要驗證特定服務(wù)的證書(shū),你可以使用 match_hostname() 函數。

如果 binary_form 形參為 True,并且提供了證書(shū),此方法會(huì )將整個(gè)證書(shū)的 DER 編碼形式作為字節序列返回,或者如果對等方未提供證書(shū)則返回 None。 對等方是否提供證書(shū)取決于 SSL 套接字的角色:

  • 對于客戶(hù)端 SSL 套接字,服務(wù)器將總是提供證書(shū),無(wú)論是否需要進(jìn)行驗證;

  • 對于服務(wù)器 SSL 套接字,客戶(hù)端將僅在服務(wù)器要求時(shí)才提供證書(shū);因此如果你使用了 CERT_NONE (而不是 CERT_OPTIONALCERT_REQUIRED) 則 getpeercert() 將返回 None。

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

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

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

SSLSocket.cipher()?

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

SSLSocket.shared_ciphers()?

返回在握手期間由客戶(hù)端共享的密碼列表。 所返回列表的每個(gè)條目都是由三個(gè)值組成的元組,其中包括密碼名稱(chēng),定義其使用方式的 SSL 協(xié)議版本,以及密碼所使用的加密比特位數。 如果尚未建立連接或套接字為客戶(hù)端套接字則 shared_ciphers() 將返回 None。

3.5 新版功能.

SSLSocket.compression()?

以字符串形式返回所使用的壓縮算法,或者如果連接沒(méi)有使用壓縮則返回 None。

如果高層級的協(xié)議支持自己的壓縮機制,你可以使用 OP_NO_COMPRESSION 來(lái)禁用 SSL 層級的壓縮。

3.3 新版功能.

SSLSocket.get_channel_binding(cb_type='tls-unique')?

為當前連接獲取字節串形式的通道綁定數據。 如果尚未連接或握手尚未完成則返回 None。

cb_type 形參允許選擇需要的通道綁定類(lèi)型。 有效的通道綁定類(lèi)型在 CHANNEL_BINDING_TYPES 列表中列出。 目前只支持由 RFC 5929 所定義的 'tls-unique' 通道綁定。 如果請求了一個(gè)不受支持的通道綁定類(lèi)型則將引發(fā) ValueError。

3.3 新版功能.

SSLSocket.selected_alpn_protocol()?

返回在 TLS 握手期間所選擇的協(xié)議。 如果 SSLContext.set_alpn_protocols() 未被調用,如果另一方不支持 ALPN,如果此套接字不支持任何客戶(hù)端所用的協(xié)議,或者如果握手尚未發(fā)生,則將返回 None。

3.5 新版功能.

SSLSocket.selected_npn_protocol()?

返回在Return the higher-level protocol that was selected during the TLS/SSL 握手期間所選擇的高層級協(xié)議。 如果 SSLContext.set_npn_protocols() 未被調用,或者如果另一方不支持 NPN,或者如果握手尚未發(fā)生,則將返回 None。

3.3 新版功能.

3.10 版后已移除: NPN 已被 ALPN 取代。

SSLSocket.unwrap()?

執行 SSL 關(guān)閉握手,這會(huì )從下層的套接字中移除 TLS 層,并返回下層的套接字對象。 這可被用來(lái)通過(guò)一個(gè)連接將加密操作轉為非加密。 返回的套接字應當總是被用于同連接另一方的進(jìn)一步通信,而不是原始的套接字。

SSLSocket.verify_client_post_handshake()?

向一個(gè) TLS 1.3 客戶(hù)端請求握手后身份驗證(PHA)。 只有在初始 TLS 握手之后且雙方都啟用了 PHA 的情況下才能為服務(wù)器端套接字的 TLS 1.3 連接啟用 PHA,參見(jiàn) SSLContext.post_handshake_auth。

此方法不會(huì )立即執行證書(shū)交換。 服務(wù)器端會(huì )在下一次寫(xiě)入事件期間發(fā)送 CertificateRequest 并期待客戶(hù)端在下一次讀取事件期間附帶證書(shū)進(jìn)行響應。

如果有任何前置條件未被滿(mǎn)足(例如非 TLS 1.3,PHA 未啟用),則會(huì )引發(fā) SSLError。

備注

僅在 OpenSSL 1.1.1 且 TLS 1.3 被啟用時(shí)可用。 沒(méi)有 TLS 1.3 支持,此方法將引發(fā) NotImplementedError。

3.8 新版功能.

SSLSocket.version()?

Return the actual SSL protocol version negotiated by the connection as a string, or None if no secure connection is established. As of this writing, possible return values include "SSLv2", "SSLv3", "TLSv1", "TLSv1.1" and "TLSv1.2". Recent OpenSSL versions may define more return values.

3.5 新版功能.

SSLSocket.pending()?

返回在連接上等待被讀取的已解密字節數。

SSLSocket.context?

此 SSL 套接字所聯(lián)結的 SSLContext 對象。 如果 SSL 套接字是使用已棄用的 wrap_socket() 函數 (而非 SSLContext.wrap_socket()) 創(chuàng )建的,則這將是為此 SSL 套接字創(chuàng )建的自定義上下文對象。

3.2 新版功能.

SSLSocket.server_side?

一個(gè)布爾值,對于服務(wù)器端套接字為 True 而對于客戶(hù)端套接字則為 False。

3.2 新版功能.

SSLSocket.server_hostname?

服務(wù)器的主機名: str 類(lèi)型,對于服務(wù)器端套接字或者如果構造器中未指定主機名則為 None。

3.2 新版功能.

在 3.7 版更改: 現在該屬性將始終為 ASCII 文本。 當 server_hostname 為一個(gè)國際化域名(IDN)時(shí),該屬性現在會(huì )保存為 A 標簽形式 ("xn--pythn-mua.org") 而非 U 標簽形式 ("pyth?n.org")。

SSLSocket.session?

用于 SSL 連接的 SSLSession。 該會(huì )話(huà)將在執行 TLS 握手后對客戶(hù)端和服務(wù)器端套接字可用。 對于客戶(hù)端套接字該會(huì )話(huà)可以在調用 do_handshake() 之前被設置以重用一個(gè)會(huì )話(huà)。

3.6 新版功能.

SSLSocket.session_reused?

3.6 新版功能.

SSL 上下文?

3.2 新版功能.

SSL 上下文可保存各種比單獨 SSL 連接壽命更長(cháng)的數據,例如 SSL 配置選項,證書(shū)和私鑰等。 它還可為服務(wù)器端套接字管理緩存,以加快來(lái)自相同客戶(hù)端的重復連接。

class ssl.SSLContext(protocol=None)?

創(chuàng )建一個(gè)新的 SSL 上下文。 你可以傳入 protocol,它必須為此模塊中定義的 PROTOCOL_* 常量之一。 該形參指定要使用哪個(gè) SSL 協(xié)議版本。 通常,服務(wù)器會(huì )選擇一個(gè)特定的協(xié)議版本,而客戶(hù)端必須適應服務(wù)器的選擇。 大多數版本都不能與其他版本互操作。 如果未指定,則默認值為 PROTOCOL_TLS;它提供了與其他版本的最大兼容性。

這個(gè)表顯示了客戶(hù)端(橫向)的哪個(gè)版本能夠連接服務(wù)器(縱向)的哪個(gè)版本。

客戶(hù)端 / 服務(wù)器

SSLv2

SSLv3

TLS 3

TLSv1

TLSv1.1

TLSv1.2

SSLv2

1

SSLv3

2

TLS (SSLv23) 3

1

2

TLSv1

TLSv1.1

TLSv1.2

備注

1(1,2)

SSLContext 默認設置 OP_NO_SSLv2 以禁用 SSLv2。

2(1,2)

SSLContext 默認設置 OP_NO_SSLv3 以禁用 SSLv3。

3(1,2)

TLS 1.3 協(xié)議在 OpenSSL >= 1.1.1 中設置 PROTOCOL_TLS 時(shí)可用。 沒(méi)有專(zhuān)門(mén)針對 TLS 1.3 的 PROTOCOL 常量。

參見(jiàn)

create_default_context()ssl 為特定目標選擇安全設置。

在 3.6 版更改: 上下文會(huì )使用安全默認值來(lái)創(chuà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 除外)。

3.10 版后已移除: 不帶協(xié)議參數的 SSLContext 已廢棄。將來(lái),上下文類(lèi)會(huì )要求使用 PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER 協(xié)議。

在 3.10 版更改: 現在默認的密碼套件只包含安全的 AES 和 ChaCha20 密碼,具有前向保密性和安全級別2。禁止使用少于 2048 位的 RSA 和 DH 密鑰以及少于 224 位的ECC密鑰。 PROTOCOL_TLS 、 PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER 至少使用 TLS 1.2 版本。

SSLContext 對象具有以下方法和屬性:

SSLContext.cert_store_stats()?

獲取以字典表示的有關(guān)已加載的 X.509 證書(shū)數量,被標記為 CA 證書(shū)的 X.509 證書(shū)數量以及證書(shū)吊銷(xiāo)列表的統計信息。

具有一個(gè) CA 證書(shū)和一個(gè)其他證書(shū)的上下文示例:

>>>
>>> context.cert_store_stats()
{'crl': 0, 'x509_ca': 1, 'x509': 2}

3.4 新版功能.

SSLContext.load_cert_chain(certfile, keyfile=None, password=None)?

Load a private key and the corresponding certificate. The certfile string must be the path to a single file in PEM format containing the certificate as well as any number of CA certificates needed to establish the certificate's authenticity. The keyfile string, if present, must point to a file containing the private key. Otherwise the private key will be taken from certfile as well. See the discussion of 證書(shū) for more information on how the certificate is stored in the certfile.

password 參數可以是一個(gè)函數,調用時(shí)將得到用于解密私鑰的密碼。 它在私鑰被加密且需要密碼時(shí)才會(huì )被調用。 它調用時(shí)將不帶任何參數,并且應當返回一個(gè)字符串、字節串或字節數組。 如果返回值是一個(gè)字符串,在用它解密私鑰之前它將以 UTF-8 進(jìn)行編碼。 或者也可以直接將字符串、字節串或字節數組值作為 password 參數提供。 如果私鑰未被加密且不需要密碼則它將被忽略。

如果未指定 password 參數且需要一個(gè)密碼,將會(huì )使用 OpenSSL 內置的密碼提示機制來(lái)交互式地提示用戶(hù)輸入密碼。

如果私鑰不能匹配證書(shū)則會(huì )引發(fā) SSLError。

在 3.3 版更改: 新增可選參數 password。

SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)?

Load a set of default "certification authority" (CA) certificates from default locations. On Windows it loads CA certs from the CA and ROOT system stores. On all systems it calls SSLContext.set_default_verify_paths(). In the future the method may load CA certificates from other locations, too.

purpose 旗標指明要加載哪一類(lèi) CA 證書(shū)。 默認設置 Purpose.SERVER_AUTH 加載被標記且被信任用于 TLS Web 服務(wù)器驗證(客戶(hù)端套接字)的證書(shū)。 Purpose.CLIENT_AUTH 則加載用于在服務(wù)器端進(jìn)行客戶(hù)端證書(shū)驗證的 CA 證書(shū)。

3.4 新版功能.

SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)?

verify_mode 不為 CERT_NONE 時(shí)加載一組用于驗證其他對等方證書(shū)的 "證書(shū)頒發(fā)機構" (CA) 證書(shū)。 必須至少指定 cafilecapath 中的一個(gè)。

此方法還可加載 PEM 或 DER 格式的證書(shū)吊銷(xiāo)列表 (CRL),為此必須正確配置 SSLContext.verify_flags。

如果存在 cafile 字符串,它應為 PEM 格式的級聯(lián) CA 證書(shū)文件的路徑。 請參閱 證書(shū) 中的討論來(lái)了解有關(guān)如何處理此文件中的證書(shū)的更多信息。

如果存在 capath 字符串,它應為包含多個(gè) PEM 格式的 CA 證書(shū)的目錄的路徑,并遵循 OpenSSL 專(zhuān)屬布局。

如果存在 cadata 對象,它應為一個(gè)或多個(gè) PEM 編碼的證書(shū)的 ASCII 字符串或者 DER 編碼的證書(shū)的 bytes-like object。 與 capath 一樣 PEM 編碼的證書(shū)之外的多余行會(huì )被忽略,但至少要有一個(gè)證書(shū)。

在 3.4 版更改: 新增可選參數 cadata

SSLContext.get_ca_certs(binary_form=False)?

獲取已離開(kāi)法人 "證書(shū)頒發(fā)機構" (CA) 證書(shū)列表。 如果 binary_form 形參為 False 則每個(gè)列表條目都是一個(gè)類(lèi)似于 SSLSocket.getpeercert() 輸出的字典。 在其他情況下此方法將返回一個(gè) DER 編碼的證書(shū)的列表。 返回的列表不包含來(lái)自 capath 的證書(shū),除非 SSL 連接請求并加載了一個(gè)證書(shū)。

備注

capath 目錄中的證書(shū)不會(huì )被加載,除非它們已至少被使用過(guò)一次。

3.4 新版功能.

SSLContext.get_ciphers()?

獲取已啟用密碼的列表。 該列表將按密碼的優(yōu)先級排序。 參見(jiàn) SSLContext.set_ciphers()。

示例:

>>>
>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
>>> ctx.get_ciphers()
[{'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'}]

3.6 新版功能.

SSLContext.set_default_verify_paths()?

從構建 OpenSSL 庫時(shí)定義的文件系統路徑中加載一組默認的 "證書(shū)頒發(fā)機構" (CA) 證書(shū)。 不幸的是,沒(méi)有一種簡(jiǎn)單的方式能知道此方法是否執行成功:如果未找到任何證書(shū)也不會(huì )返回錯誤。 不過(guò),當 OpenSSL 庫是作為操作系統的一部分被提供時(shí),它的配置應當是正確的。

SSLContext.set_ciphers(ciphers)?

為使用此上下文創(chuàng )建的套接字設置可用密碼。 它應當為 OpenSSL 密碼列表格式 的字符串。 如果沒(méi)有可被選擇的密碼(由于編譯時(shí)選項或其他配置禁止使用所指定的任何密碼),則將引發(fā) SSLError。

備注

在連接后,SSL 套接字的 SSLSocket.cipher() 方法將給出當前所選擇的密碼。

TLS 1.3 密碼套件不能通過(guò) set_ciphers() 禁用。

SSLContext.set_alpn_protocols(protocols)?

指定在 SSL/TLS 握手期間套接字應當通告的協(xié)議。 它應為由 ASCII 字符串組成的列表,例如 ['http/1.1', 'spdy/2'],按首選順序排列。 協(xié)議的選擇將在握手期間發(fā)生,并依據 RFC 7301 來(lái)執行。 在握手成功后,SSLSocket.selected_alpn_protocol() 方法將返回已達成一致的協(xié)議。

如果 HAS_ALPNFalse 則此方法將引發(fā) NotImplementedError。

3.5 新版功能.

SSLContext.set_npn_protocols(protocols)?

指定在Specify which protocols the socket should advertise during the SSL/TLS 握手期間套接字應當通告的協(xié)議。 它應為由字符串組成的列表,例如 ['http/1.1', 'spdy/2'],按首選順序排列。 協(xié)議的選擇將在握手期間發(fā)生,并將依據 應用層協(xié)議協(xié)商 來(lái)執行。 在握手成功后,SSLSocket.selected_npn_protocol() 方法將返回已達成一致的協(xié)議。

如果 HAS_NPNFalse 則此方法將引發(fā) NotImplementedError。

3.3 新版功能.

3.10 版后已移除: NPN 已被 ALPN 取代。

SSLContext.sni_callback?

注冊一個(gè)回調函數,當 TLS 客戶(hù)端指定了一個(gè)服務(wù)器名稱(chēng)提示時(shí),該回調函數將在 SSL/TLS 服務(wù)器接收到 TLS Client Hello 握手消息后被調用。 服務(wù)器名稱(chēng)提示機制的定義見(jiàn) RFC 6066 section 3 - Server Name Indication。

每個(gè) SSLContext 只能設置一個(gè)回調。 如果 sni_callback 被設置為 None 則會(huì )禁用回調。 對該函數的后續調用將禁用之前注冊的回調。

此回調函數將附帶三個(gè)參數來(lái)調用;第一個(gè)參數是 ssl.SSLSocket,第二個(gè)參數是代表客戶(hù)端準備與之通信的服務(wù)器的字符串 (或者如果 TLS Client Hello 不包含服務(wù)器名稱(chēng)則為 None) 而第三個(gè)參數是原來(lái)的 SSLContext。 服務(wù)器名稱(chēng)參數為文本形式。 對于國際化域名,服務(wù)器名稱(chēng)是一個(gè) IDN A 標簽 ("xn--pythn-mua.org")。

此回調的一個(gè)典型用法是將 ssl.SSLSocketSSLSocket.context 屬性修改為一個(gè) SSLContext 類(lèi)型的新對象,該對象代表與服務(wù)器相匹配的證書(shū)鏈。

Due to the early negotiation phase of the TLS connection, only limited methods and attributes are usable like SSLSocket.selected_alpn_protocol() and SSLSocket.context. The SSLSocket.getpeercert(), SSLSocket.cipher() and SSLSocket.compression() methods require that the TLS connection has progressed beyond the TLS Client Hello and therefore will not return meaningful values nor can they be called safely.

sni_callback 函數必須返回 None 以允許 TLS 協(xié)商繼續進(jìn)行。 如果想要 TLS 失敗,則可以返回常量 ALERT_DESCRIPTION_*。 其他返回值將導致 TLS 的致命錯誤 ALERT_DESCRIPTION_INTERNAL_ERROR。

如果從 sni_callback 函數引發(fā)了異常,則 TLS 連接將終止并發(fā)出 TLS 致命警告消息 ALERT_DESCRIPTION_HANDSHAKE_FAILURE。

如果 OpenSSL library 庫在構建時(shí)定義了 OPENSSL_NO_TLSEXT 則此方法將返回 NotImplementedError。

3.7 新版功能.

SSLContext.set_servername_callback(server_name_callback)?

這是被保留用于向下兼容的舊式 API。 在可能的情況下,你應當改用 sni_callback。 給出的 server_name_callback 類(lèi)似于 sni_callback,不同之處在于當服務(wù)器主機名是 IDN 編碼的國際化域名時(shí),server_name_callback 會(huì )接收到一個(gè)已編碼的 U 標簽 ("pyth?n.org")。

如果發(fā)生了服務(wù)器名稱(chēng)解碼錯誤。 TLS 連接將終止并向客戶(hù)端發(fā)出 ALERT_DESCRIPTION_INTERNAL_ERROR 最嚴重 TLS 警告消息。

3.4 新版功能.

SSLContext.load_dh_params(dhfile)?

加載密鑰生成參數用于 Diffie-Hellman (DH) 密鑰交換。 使用 DH 密鑰交換能以消耗(服務(wù)器和客戶(hù)端的)計算資源為代價(jià)提升前向保密性。 dhfile 參數應當為指向一個(gè)包含 PEM 格式的 DH 形參的文件的路徑。

此設置不會(huì )應用于客戶(hù)端套接字。 你還可以使用 OP_SINGLE_DH_USE 選項來(lái)進(jìn)一步提升安全性。

3.3 新版功能.

SSLContext.set_ecdh_curve(curve_name)?

為基于橢圓曲線(xiàn)的 Elliptic Curve-based Diffie-Hellman (ECDH) 密鑰交換設置曲線(xiàn)名稱(chēng)。 ECDH 顯著(zhù)快于常規 DH 同時(shí)據信同樣安全。 curve_name 形參應為描述某個(gè)知名橢圓曲線(xiàn)的字符串,例如受到廣泛支持的曲線(xiàn) prime256v1。

此設置不會(huì )應用于客戶(hù)端套接字。 你還可以使用 OP_SINGLE_ECDH_USE 選項來(lái)進(jìn)一步提升安全性。

如果 HAS_ECDHFalse 則此方法將不可用。

3.3 新版功能.

參見(jiàn)

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è)現有的 Python 套接字 sock 并返回一個(gè) SSLContext.sslsocket_class 的實(shí)例 (默認為 SSLSocket)。 返回的 SSL 套接字會(huì )綁定上下文、設置以及證書(shū)。 sock 必須是一個(gè) SOCK_STREAM 套接字;其他套接字類(lèi)型不被支持。

形參 server_side 是一個(gè)布爾值,它標明希望從該套接字獲得服務(wù)器端行為還是客戶(hù)端行為。

對于客戶(hù)端套接字,上下文的構造會(huì )延遲執行;如果下層的套接字尚未連接,上下文的構造將在對套接字調用 connect() 之后執行。 對于服務(wù)器端套接字,如果套接字沒(méi)有遠端對等方,它會(huì )被視為一個(gè)監聽(tīng)套接字,并且服務(wù)器端 SSL 包裝操作會(huì )在通過(guò) accept() 方法所接受的客戶(hù)端連接上自動(dòng)執行。 此方法可能會(huì )引發(fā) SSLError。

在客戶(hù)端連接上,可選形參 server_hostname 指定所要連接的服務(wù)的主機名。 這允許單個(gè)服務(wù)器托管具有單獨證書(shū)的多個(gè)基于 SSL 的服務(wù),很類(lèi)似于 HTTP 虛擬主機。 如果 server_side 為真值則指定 server_hostname 將引發(fā) ValueError。

形參 do_handshake_on_connect 指明是否要在調用 socket.connect() 之后自動(dòng)執行 SSL 握手,還是要通過(guò)發(fā)起調用 SSLSocket.do_handshake() 方法讓?xiě)贸绦蝻@式地調用它。 顯式地調用 SSLSocket.do_handshake() 可給予程序對握手中所涉及的套接字 I/O 阻塞行為的控制。

形參 suppress_ragged_eofs 指明 SSLSocket.recv() 方法應當如何從連接的另一端發(fā)送非預期的 EOF 信號。 如果指定為 True (默認值),它將返回正常的 EOF (空字節串對象) 來(lái)響應從下層套接字引發(fā)的非預期的 EOF 錯誤;如果指定為 False,它將向調用方引發(fā)異常。

session,參見(jiàn) session。

在 3.5 版更改: 總是允許傳送 server_hostname,即使 OpenSSL 沒(méi)有 SNI。

在 3.6 版更改: 增加了 session 參數。

在 3.7 版更改: The method returns an instance of SSLContext.sslsocket_class instead of hard-coded SSLSocket.

SSLContext.sslsocket_class?

SSLContext.wrap_socket() 的返回類(lèi)型,默認為 SSLSocket。 該屬性可以在類(lèi)實(shí)例上被重載以便返回自定義的 SSLSocket 的子類(lèi)。

3.7 新版功能.

SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)?

包裝 BIO 對象 incomingoutgoing 并返回一個(gè) SSLContext.sslobject_class (默認為 SSLObject) 的實(shí)例。 SSL 例程將從 BIO 中讀取輸入數據并將數據寫(xiě)入到 outgoing BIO。

server_side, server_hostnamesession 形參具有與 SSLContext.wrap_socket() 中相同的含義。

在 3.6 版更改: 增加了 session 參數。

在 3.7 版更改: The method returns an instance of SSLContext.sslobject_class instead of hard-coded SSLObject.

SSLContext.sslobject_class?

SSLContext.wrap_bio() 的返回類(lèi)型,默認為 SSLObject。 該屬性可以在類(lèi)實(shí)例上被重載以便返回自定義的 SSLObject 的子類(lèi)。

3.7 新版功能.

SSLContext.session_stats()?

獲取該上下文創(chuàng )建或管理的 SSL 會(huì )話(huà)的統計數據。返回一個(gè)字典,將每`塊信息 <https://www.openssl.org/docs/man1.1.1/ssl/SSL_CTX_sess_number.html>`_ 映射到數字值。例如,下面是自該上下文創(chuàng )建以來(lái)會(huì )話(huà)緩存中的總點(diǎn)擊率和失誤率:

>>>
>>> stats = context.session_stats()
>>> stats['hits'], stats['misses']
(0, 0)
SSLContext.check_hostname?

是否要將匹配 SSLSocket.do_handshake() 中對等方證書(shū)的主機名。 該上下文的 verify_mode 必須被設為 CERT_OPTIONALCERT_REQUIRED,并且你必須將 server_hostname 傳給 wrap_socket() 以便匹配主機名。 啟用主機名檢查會(huì )自動(dòng)將 verify_modeCERT_NONE 設為 CERT_REQUIRED。 只要啟用了主機名檢查就無(wú)法將其設回 CERT_NONE。 PROTOCOL_TLS_CLIENT 協(xié)議默認啟用主機名檢查。 對于其他協(xié)議,則必須顯式地啟用主機名檢查。

示例:

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 版更改: 現在當主機名檢查被啟用且 verify_modeCERT_NONE 時(shí) verify_mode 會(huì )自動(dòng)更改為 CERT_REQUIRED。 在之前版本中同樣的操作將失敗并引發(fā) ValueError。

SSLContext.keylog_filename?

每當生成或接收到密鑰時(shí),將 TLS 密鑰寫(xiě)入到一個(gè)密鑰日志文件。 密鑰日志文件的設計僅適用于調試目的。 文件的格式由 NSS 指明并為許多流量分析工具例如 Wireshark 所使用。 日志文件會(huì )以追加模式打開(kāi)。 寫(xiě)入操作會(huì )在線(xiàn)程之間同步,但不會(huì )在進(jìn)程之間同步。

3.8 新版功能.

SSLContext.maximum_version?

一個(gè)代表所支持的最高 TLS 版本的 TLSVersion 枚舉成員。 該值默認為 TLSVersion.MAXIMUM_SUPPORTED。 這個(gè)屬性對于 PROTOCOL_TLS, PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER 以外的其他協(xié)議來(lái)說(shuō)都是只讀的。

maximum_version, minimum_versionSSLContext.options 等屬性都會(huì )影響上下文所支持的 SSL 和 TLS 版本。 這個(gè)實(shí)現不會(huì )阻止無(wú)效的組合。 例如一個(gè) optionsOP_NO_TLSv1_2maximum_version 設為 TLSVersion.TLSv1_2 的上下文將無(wú)法建立 TLS 1.2 連接。

3.7 新版功能.

SSLContext.minimum_version?

SSLContext.maximum_version 類(lèi)似,區別在于它是所支持的最低版本或為 TLSVersion.MINIMUM_SUPPORTED。

3.7 新版功能.

SSLContext.num_tickets?

控制 TLS_PROTOCOL_SERVER 上下文的 TLS 1.3 會(huì )話(huà)憑據數量。這個(gè)設置不會(huì )影響 TLS 1.0 - 1.2 的連接。

3.8 新版功能.

SSLContext.options?

一個(gè)代表此上下文中所啟用的 SSL 選項集的整數。 默認值為 OP_ALL,但你也可以通過(guò)在選項間進(jìn)行 OR 運算來(lái)指定其他選項例如 OP_NO_SSLv2。

在 3.6 版更改: SSLContext.options 返回 Options 旗標:

>>>
>>> ssl.create_default_context().options  
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>

3.7 版后已移除: 自 OpenSSL 1.1.0 起,所有 OP_NO_SSL*OP_NO_TLS* 選項已被棄用,請改用新的 SSLContext.minimum_versionSSLContext.maximum_version。

SSLContext.post_handshake_auth?

啟用 TLS 1.3 握手后客戶(hù)端身份驗證。 握手后驗證默認是被禁用的,服務(wù)器只能在初始握手期間請求 TLS 客戶(hù)端證書(shū)。 當啟用時(shí),服務(wù)器可以在握手之后的任何時(shí)候請求 TLS 客戶(hù)端證書(shū)。

當在客戶(hù)端套接字上啟用時(shí),客戶(hù)端會(huì )向服務(wù)器發(fā)信號說(shuō)明它支持握手后身份驗證。

當在服務(wù)器端套接字上啟用時(shí),SSLContext.verify_mode 也必須被設為 CERT_OPTIONALCERT_REQUIRED。 實(shí)際的客戶(hù)端證書(shū)交換會(huì )被延遲直至 SSLSocket.verify_client_post_handshake() 被調用并執行了一些 I/O 操作后再進(jìn)行。

3.8 新版功能.

SSLContext.protocol?

構造上下文時(shí)所選擇的協(xié)議版本。 這個(gè)屬性是只讀的。

SSLContext.hostname_checks_common_name?

在沒(méi)有目標替代名稱(chēng)擴展的情況下 check_hostname 是否要回退為驗證證書(shū)的通用名稱(chēng)(默認為真值)。

3.7 新版功能.

在 3.10 版更改: 此旗標在 OpenSSL 1.1.1k 之前的版本上不起作用。 Python 3.8.9, 3.9.3, 和 3.10 包含了針對之前版本的變通處理。

SSLContext.security_level?

整數值,代表上下文的 安全級別。 本屬性只讀。

3.10 新版功能.

SSLContext.verify_flags?

證書(shū)驗證操作的標志位??梢杂谩盎颉钡姆绞浇M合在一起設置 VERIFY_CRL_CHECK_LEAF 這類(lèi)標志。默認情況下,OpenSSL 既不需要也不驗證證書(shū)吊銷(xiāo)列表(CRL)。

3.4 新版功能.

在 3.6 版更改: SSLContext.verify_flags 返回 VerifyFlags 旗標:

>>>
>>> ssl.create_default_context().verify_flags  
<VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
SSLContext.verify_mode?

是否要嘗試驗證其他對等方的證書(shū)以及如果驗證失敗應采取何種行為。 該屬性值必須為 CERT_NONE, CERT_OPTIONALCERT_REQUIRED 之一。

在 3.6 版更改: SSLContext.verify_mode 返回 VerifyMode 枚舉:

>>>
>>> ssl.create_default_context().verify_mode  
<VerifyMode.CERT_REQUIRED: 2>

證書(shū)?

總的來(lái)說(shuō)證書(shū)是公鑰/私鑰系統的一個(gè)組成部分。 在這個(gè)系統中,每 個(gè) 主體 (可能是一臺機器、一個(gè)人或者一個(gè)組織) 都會(huì )分配到唯一的包含兩部分的加密密鑰。 一部分密鑰是公開(kāi)的,稱(chēng)為 公鑰;另一部分密鑰是保密的,稱(chēng)為 私鑰。 這兩個(gè)部分是互相關(guān)聯(lián)的,就是說(shuō)如果你用其中一個(gè)部分來(lái)加密一條消息,你將能用并且 只能 用另一個(gè)部分來(lái)解密它。

在一個(gè)證書(shū)中包含有兩個(gè)主體的相關(guān)信息。 它包含 目標方 的名稱(chēng)和目標方的公鑰。 它還包含由第二個(gè)主體 頒發(fā)方 所發(fā)布的聲明:目標方的身份與他們所宣稱(chēng)的一致,包含的公鑰也確實(shí)是目標方的公鑰。 頒發(fā)方的聲明使用頒發(fā)方的私鑰進(jìn)行簽名,該私鑰的內容只有頒發(fā)方自己才知道。 但是,任何人都可以找到頒發(fā)方的公鑰,用它來(lái)解密這個(gè)聲明,并將其與證書(shū)中的其他信息進(jìn)行比較來(lái)驗證頒發(fā)方聲明的真實(shí)性。 證書(shū)還包含有關(guān)其有效期限的信息。 這被表示為兩個(gè)字段,即 "notBefore" 和 "notAfter"。

在 Python 中應用證書(shū)時(shí),客戶(hù)端或服務(wù)器可以用證書(shū)來(lái)證明自己的身份。 還可以要求網(wǎng)絡(luò )連接的另一方提供證書(shū),提供的證書(shū)可以用于驗證以滿(mǎn)足客戶(hù)端或服務(wù)器的驗證要求。 如果驗證失敗,連接嘗試可被設置為引發(fā)一個(gè)異常。 驗證是由下層的 OpenSSL 框架來(lái)自動(dòng)執行的;應用程序本身不必關(guān)注其內部的機制。 但是應用程序通常需要提供一組證書(shū)以允許此過(guò)程的發(fā)生。

Python 使用文件來(lái)包含證書(shū)。 它們應當采用 "PEM" 格式 (參見(jiàn) RFC 1422),這是一種帶有頭部行和尾部行的 base-64 編碼包裝形式:

-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

證書(shū)鏈?

包含證書(shū)的 Python 文件可以包含一系列的證書(shū),有時(shí)被稱(chēng)為 證書(shū)鏈。 這個(gè)證書(shū)鏈應當以 "作為" 客戶(hù)端或服務(wù)器的主體的專(zhuān)屬證書(shū)打頭,然后是證書(shū)頒發(fā)方的證書(shū),然后是 上述 證書(shū)的頒發(fā)方的證書(shū),證書(shū)鏈就這樣不斷上溯直到你得到一個(gè) 自簽名 的證書(shū),即具有相同目標方和頒發(fā)方的證書(shū),有時(shí)也稱(chēng)為 根證書(shū)。 在證書(shū)文件中這些證書(shū)應當被拼接為一體。 例如,假設我們有一個(gè)包含三個(gè)證書(shū)的證書(shū)鏈,以我們的服務(wù)器證書(shū)打頭,然后是為我們的服務(wù)器證書(shū)簽名的證書(shū)頒發(fā)機構的證書(shū),最后是為證書(shū)頒發(fā)機構的證書(shū)頒發(fā)證書(shū)的機構的根證書(shū):

-----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 證書(shū)?

如果你想要求對連接的另一方的證書(shū)進(jìn)行驗證,你必須提供一個(gè) "CA 證書(shū)" 文件,其中包含了你愿意信任的每個(gè)頒發(fā)方的證書(shū)鏈。 同樣地,這個(gè)文件的內容就是這些證書(shū)鏈拼接在一起的結果。 為了進(jìn)行驗證,Python 將使用它在文件中找到的第一個(gè)匹配的證書(shū)鏈。 可以通過(guò)調用 SSLContext.load_default_certs() 來(lái)使用系統平臺的證書(shū)文件,這可以由 create_default_context() 自動(dòng)完成。

合并的密鑰和證書(shū)?

私鑰往往與證書(shū)存儲在相同的文件中;在此情況下,只需要將 certfile 形參傳給 SSLContext.load_cert_chain()wrap_socket()。 如果私鑰是與證書(shū)一起存儲的,則它應當放在證書(shū)鏈的第一個(gè)證書(shū)之前:

-----BEGIN RSA PRIVATE KEY-----
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

自簽名證書(shū)?

如果你準備創(chuàng )建一個(gè)提供 SSL 加密連接服務(wù)的服務(wù)器,你需要為該服務(wù)獲取一份證書(shū)。 有許多方式可以獲取合適的證書(shū),例如從證書(shū)頒發(fā)機構購買(mǎi)。 另一種常見(jiàn)做法是生成自簽名證書(shū)。 生成自簽名證書(shū)的最簡(jiǎn)單方式是使用 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
%

自簽名證書(shū)的缺點(diǎn)在于它是它自身的根證書(shū),因此不會(huì )存在于別人的已知(且信任的)根證書(shū)緩存當中。

例子?

檢測 SSL 支持?

要檢測一個(gè) Python 安裝版中是否帶有 SSL 支持,用戶(hù)代碼應當使用以下例程:

try:
    import ssl
except ImportError:
    pass
else:
    ...  # do something that requires SSL support

客戶(hù)端操作?

這個(gè)例子創(chuàng )建了一個(gè) SSL 上下文并使用客戶(hù)端套接字的推薦安全設置,包括自動(dòng)證書(shū)驗證:

>>>
>>> context = ssl.create_default_context()

如果你喜歡自行調整安全設置,你可能需要從頭創(chuàng )建一個(gè)上下文(但是請請注意避免不正確的設置):

>>>
>>> context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(這段代碼假定你的操作系統將所有 CA 證書(shū)打包存放于 /etc/ssl/certs/ca-bundle.crt;如果不是這樣,你將收到報錯信息,必須修改此位置)

PROTOCOL_TLS_CLIENT 協(xié)議配置用于證書(shū)驗證和主機名驗證的上下文。 verify_mode 設為 CERT_REQUIREDcheck_hostname 設為 True。 所有其他協(xié)議都會(huì )使用不安全的默認值創(chuàng )建 SSL 上下文。

當你使用此上下文去連接服務(wù)器時(shí),CERT_REQUIREDcheck_hostname 會(huì )驗證服務(wù)器證書(shū);它將確認服務(wù)器證書(shū)使用了某個(gè) CA 證書(shū)進(jìn)行簽名,檢查簽名是否正確,并驗證其他屬性例如主機名的有效性和身份真實(shí)性:

>>>
>>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
...                            server_hostname="www.python.org")
>>> conn.connect(("www.python.org", 443))

你可以隨后獲取該證書(shū):

>>>
>>> cert = conn.getpeercert()

可視化檢查顯示證書(shū)能夠證明目標服務(wù) (即 HTTPS 主機 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}

現在 SSL 通道已建立并已驗證了證書(shū),你可以繼續與服務(wù)器對話(huà)了:

>>>
>>> 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'']

參見(jiàn)下文對于 安全考量 的討論。

服務(wù)器端操作?

對于服務(wù)器操作,通常你需要在文件中存放服務(wù)器證書(shū)和私鑰各一份。 你將首先創(chuàng )建一個(gè)包含密鑰和證書(shū)的上下文,這樣客戶(hù)端就能檢查你的身份真實(shí)性。 然后你將打開(kāi)一個(gè)套接字,將其綁定到一個(gè)端口,在其上調用 listen(),并開(kāi)始等待客戶(hù)端連接:

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.example.com', 10023))
bindsocket.listen(5)

當有客戶(hù)端連接時(shí),你將在套接字上調用 accept() 以從另一端獲取新的套接字,并使用上下文的 SSLContext.wrap_socket() 方法來(lái)為連接創(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 讀取數據并對其進(jìn)行處理,直至你結束與客戶(hù)端的會(huì )話(huà)(或客戶(hù)端結束與你的會(huì )話(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

并返回至監聽(tīng)新的客戶(hù)端連接(當然,真正的服務(wù)器應當會(huì )在單獨的線(xiàn)程中處理每個(gè)客戶(hù)端連接,或者將套接字設為 非阻塞模式 并使用事件循環(huán))。

關(guān)于非阻塞套接字的說(shuō)明?

在非阻塞模式下 SSL 套接字的行為與常規套接字略有不同。 當使用非阻塞模式時(shí),你需要注意下面這些事情:

  • 如果一個(gè) I/O 操作會(huì )阻塞,大多數 SSLSocket 方法都將引發(fā) SSLWantWriteErrorSSLWantReadError 而非 BlockingIOError。 如果有必要在下層套接字上執行讀取操作將引發(fā) SSLWantReadError,在下層套接字上執行寫(xiě)入操作則將引發(fā) SSLWantWriteError。 請注意嘗試 寫(xiě)入 到 SSL 套接字可能需要先從下層套接字 讀取,而嘗試從 SSL 套接字 讀取 則可能需要先向下層套接字 寫(xiě)入。

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

  • 調用 select() 將告訴你可以從 OS 層級的套接字讀?。ɑ蛳蚱鋵?xiě)入),但這并不意味著(zhù)在上面的 SSL 層有足夠的數據。 例如,可能只有部分 SSL 幀已經(jīng)到達。 因此,你必須準備好處理 SSLSocket.recv()SSLSocket.send() 失敗的情況,并在再次調用 select() 之后重新嘗試。

  • 相反地,由于 SSL 層具有自己的幀機制,一個(gè) SSL 套接字可能仍有可讀取的數據而 select() 并不知道這一點(diǎn)。 因此,你應當先調用 SSLSocket.recv() 取走所有潛在的可用數據,然后只在必要時(shí)對 select() 調用執行阻塞。

    (當然,類(lèi)似的保留規則在使用其他原語(yǔ)例如 poll(),或 selectors 模塊中的原語(yǔ)時(shí)也適用)

  • SSL 握手本身將是非阻塞的: SSLSocket.do_handshake() 方法必須不斷重試直至其成功返回。 下面是一個(gè)使用 select() 來(lái)等待套接字就緒的簡(jiǎn)短例子:

    while True:
        try:
            sock.do_handshake()
            break
        except ssl.SSLWantReadError:
            select.select([sock], [], [])
        except ssl.SSLWantWriteError:
            select.select([], [sock], [])
    

參見(jiàn)

asyncio 模塊支持 非阻塞 SSL 套接字 并提供了更高層級的 API。 它會(huì )使用 selectors 模塊來(lái)輪詢(xún)事件并處理 SSLWantWriteError, SSLWantReadErrorBlockingIOError 等異常。 它還會(huì )異步地執行 SSL 握手。

內存 BIO 支持?

3.5 新版功能.

自從 SSL 模塊在 Python 2.6 起被引入之后,SSLSocket 類(lèi)提供了兩個(gè)互相關(guān)聯(lián)但彼此獨立的功能分塊:

  • SSL 協(xié)議處理

  • 網(wǎng)絡(luò ) IO

網(wǎng)絡(luò ) IO API 與 socket.socket 所提供的功能一致,SSLSocket 也是從那里繼承而來(lái)的。 這允許 SSL 套接字被用作常規套接字的替代,使得向現有應用程序添加 SSL 支持變得非常容易。

將 SSL 協(xié)議處理與網(wǎng)絡(luò ) IO 結合使用通常都能運行良好,但在某些情況下則不能。 此情況的一個(gè)例子是 async IO 框架,該框架要使用不同的 IO 多路復用模型而非 (基于就緒狀態(tài)的) "在文件描述器上執行選擇/輪詢(xún)" 模型,該模型是 socket.socket 和內部 OpenSSL 套接字 IO 例程正常運行的假設前提。 這種情況在該模型效率不高的 Windows 平臺上最為常見(jiàn)。 為此還提供了一個(gè) SSLSocket 的簡(jiǎn)化形式,稱(chēng)為 SSLObject。

class ssl.SSLObject?

SSLSocket 的簡(jiǎn)化形式,表示一個(gè)不包含任何網(wǎng)絡(luò ) IO 方法的 SSL 協(xié)議實(shí)例。 這個(gè)類(lèi)通常由想要通過(guò)內存緩沖區為 SSL 實(shí)現異步 IO 的框架作者來(lái)使用。

這個(gè)類(lèi)在低層級 SSL 對象上實(shí)現了一個(gè)接口,與 OpenSSL 所實(shí)現的類(lèi)似。 此對象會(huì )捕獲 SSL 連接的狀態(tài)但其本身不提供任何網(wǎng)絡(luò ) IO。 IO 需要通過(guò)單獨的 "BIO" 對象來(lái)執行,該對象是 OpenSSL 的 IO 抽象層。

這個(gè)類(lèi)沒(méi)有公有構造器。 SSLObject 實(shí)例必須使用 wrap_bio() 方法來(lái)創(chuàng )建。 此方法將創(chuàng )建 SSLObject 實(shí)例并將其綁定到一個(gè) BIO 對。 其中 incoming BIO 用來(lái)將數據從 Python 傳遞到 SSL 協(xié)議實(shí)例,而 outgoing BIO 用來(lái)進(jìn)行數據反向傳遞。

可以使用以下方法:

SSLSocket 相比,此對象缺少下列特性:

  • 任何形式的網(wǎng)絡(luò ) IO; recv()send() 僅對下層的 MemoryBIO 緩沖區執行讀取和寫(xiě)入。

  • 不存在 do_handshake_on_connect 機制。 你必須總是手動(dòng)調用 do_handshake() 來(lái)開(kāi)始握手操作。

  • 不存在對 suppress_ragged_eofs 的處理。 所有違反協(xié)議的文件結束條件將通過(guò) SSLEOFError 異常來(lái)報告。

  • 方法 unwrap() 的調用不返回任何東西,不會(huì )如 SSL 套接字那樣返回下層的套接字。

  • server_name_callback 回調被傳給 SSLContext.set_servername_callback() 時(shí)將獲得一個(gè) SSLObject 實(shí)例而非 SSLSocket 實(shí)例作為其第一個(gè)形參。

有關(guān) SSLObject 用法的一些說(shuō)明:

在 3.7 版更改: SSLObject 的實(shí)例必須使用 wrap_bio() 來(lái)創(chuàng )建。 在較早的版本中,直接創(chuàng )建實(shí)例是可能的。 但這從未被記入文檔或是被正式支持。

SSLObject 會(huì )使用內存緩沖區與外部世界通信。 MemoryBIO 類(lèi)提供了可被用于此目的的內存緩沖區。 它包裝了一個(gè) OpenSSL 內存 BIO (Basic IO) 對象:

class ssl.MemoryBIO?

一個(gè)可被用來(lái)在 Python 和 SSL 協(xié)議實(shí)例之間傳遞數據的內存緩沖區。

pending?

返回當前存在于內存緩沖區的字節數。

eof?

一個(gè)表明內存 BIO 目前是否位于文件末尾的布爾值。

read(n=- 1)?

從內存緩沖區讀取至多 n 個(gè)字節。 如果 n 未指定或為負值,則返回全部字節數據。

write(buf)?

將字節數據從 buf 寫(xiě)入到內存 BIO。 buf 參數必須為支持緩沖區協(xié)議的對象。

返回值為寫(xiě)入的字節數,它總是與 buf 的長(cháng)度相等。

write_eof()?

將一個(gè) EOF 標記寫(xiě)入到內存 BIO。 在此方法被調用以后,再調用 write() 將是非法的。 屬性 eof will 在緩沖區當前的所有數據都被讀取之后將變?yōu)檎嬷怠?/p>

SSL 會(huì )話(huà)?

3.6 新版功能.

class ssl.SSLSession?

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

id?
time?
timeout?
ticket_lifetime_hint?
has_ticket?

安全考量?

最佳默認值?

針對 客戶(hù)端使用,如果你對于安全策略沒(méi)有任何特殊要求,則強烈推薦你使用 create_default_context() 函數來(lái)創(chuàng )建你的 SSL 上下文。 它將加載系統的受信任 CA 證書(shū),啟用證書(shū)驗證和主機名檢查,并嘗試合理地選擇安全的協(xié)議和密碼設置。

例如,以下演示了你應當如何使用 smtplib.SMTP 類(lèi)來(lái)創(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')

如果連接需要客戶(hù)端證書(shū),可使用 SSLContext.load_cert_chain() 來(lái)添加。

作為對比,如果你通過(guò)自行調用 SSLContext 構造器來(lái)創(chuàng )建 SSL 上下文,它默認將不會(huì )啟用證書(shū)驗證和主機名檢查。 如果你這樣做,請閱讀下面的段落以達到良好的安全級別。

手動(dòng)設置?

驗證證書(shū)?

當直接調用 SSLContext 構造器時(shí),默認會(huì )使用 CERT_NONE。 由于它不會(huì )驗證對等方的身份真實(shí)性,因此是不安全的,特別是在客戶(hù)端模式下,大多數時(shí)候你都希望能保證你所連接的服務(wù)器的身份真實(shí)性。 因此,當處于客戶(hù)端模式時(shí),強烈推薦使用 CERT_REQUIRED。 但是,光這樣還不夠;你還必須檢查服務(wù)器證書(shū),這可以通過(guò)調用 SSLSocket.getpeercert() 來(lái)獲取并匹配目標服務(wù)。 對于許多協(xié)議和應用來(lái)說(shuō),服務(wù)可通過(guò)主機名來(lái)標識;在此情況下,可以使用 match_hostname() 函數。 這種通用檢測會(huì )在 SSLContext.check_hostname 被啟用時(shí)自動(dòng)執行。

在 3.7 版更改: 主機名匹配現在是由 OpenSSL 來(lái)執行的。 Python 不會(huì )再使用 match_hostname()。

在服務(wù)器模式下,如果你想要使用 SSL 層來(lái)驗證客戶(hù)端(而不是使用更高層級的驗證機制),你也必須要指定 CERT_REQUIRED 并以類(lèi)似方式檢查客戶(hù)端證書(shū)。

協(xié)議版本?

SSL 版本 2 和 3 被認為是不安全的因而使用它們會(huì )有風(fēng)險。 如果你想要客戶(hù)端和服務(wù)器之間有最大的兼容性,推薦使用 PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER 作為協(xié)議版本。 SSLv2 和 SSLv3 默認會(huì )被禁用。

>>>
>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.minimum_version = ssl.TLSVersion.TLSv1_3
>>> client_context.maximum_version = ssl.TLSVersion.TLSv1_3

前面創(chuàng )建的 SSL 上下文將只允許 TLSv1.2 及更新版本(如果你的系統支持)的服務(wù)器連接。 PROTOCOL_TLS_CLIENT 默認會(huì )使用證書(shū)驗證和主機名檢查。 你必須將證書(shū)加載到上下文中。

密碼選擇?

如果你有更高級的安全要求,也可以通過(guò) SSLContext.set_ciphers() 方法在協(xié)商 SSL 會(huì )話(huà)時(shí)對所啟用的加密進(jìn)行微調。 從 Python 3.2.3 開(kāi)始,ssl 默認會(huì )禁用某些較弱的加密,但你還可能希望進(jìn)一步限制加密選項。 請確保仔細閱讀 OpenSSL 文檔中有關(guān) 加密列表格式 的部分。 如果你想要檢查給定的加密列表啟用了哪些加密,可以使用 SSLContext.get_ciphers() 或所在系統的 openssl ciphers 命令。

多進(jìn)程?

如果使用此模塊作為多進(jìn)程應用的一部分(例如使用 multiprocessingconcurrent.futures 模塊),請注意 OpenSSL 的內部隨機數字生成器并不能正確處理分支進(jìn)程。 應用程序必須修改父進(jìn)程的 PRNG 狀態(tài),如果它們要使用任何包含 os.fork() 的 SSL 特性的話(huà)。 任何對 RAND_add(), RAND_bytes()RAND_pseudo_bytes() 都可以 做到這一點(diǎn)。

TLS 1.3?

3.7 新版功能.

TLS 1.3 協(xié)議的行為與低版本的 TLS/SSL 略有不同。某些 TLS 1.3 新特性還不可用。

  • TLS 1.3 使用一組不同的加密套件集。 默認情況下所有 AES-GCM 和 ChaCha20 加密套件都會(huì )被啟用。 SSLContext.set_ciphers() 方法還不能啟用或禁用任何 TLS 1.3 加密,但 SSLContext.get_ciphers() 會(huì )返回它們。

  • 會(huì )話(huà)憑據不再會(huì )作為初始握手的組成部分被發(fā)送而是以不同的方式來(lái)處理。 SSLSocket.sessionSSLSession 與 TLS 1.3 不兼容。

  • 客戶(hù)端證書(shū)在初始握手期間也不會(huì )再被驗證。 服務(wù)器可以在任何時(shí)候請求證書(shū)。 客戶(hù)端會(huì )在它們從服務(wù)器發(fā)送或接收應用數據時(shí)處理證書(shū)請求。

  • 早期數據、延遲的 TLS 客戶(hù)端證書(shū)請求、簽名算法配置和密鑰重生成等 TLS 1.3 特性尚未被支持。