ssl
— 用於套接字物件的 TLS/SSL 包裝器¶
原始碼: Lib/ssl.py
此模組提供對網路套接字的傳輸層安全性(通常稱為“安全套接字層”)加密和對等身份驗證功能的訪問,包括客戶端和伺服器端。此模組使用 OpenSSL 庫。只要該平臺上安裝了 OpenSSL,它就可以在所有現代 Unix 系統、Windows、macOS 以及可能的其他平臺上使用。
註解
某些行為可能依賴於平臺,因為會呼叫作業系統套接字 API。安裝的 OpenSSL 版本也可能導致行為上的差異。例如,TLSv1.3 隨 OpenSSL 1.1.1 版本一起提供。
警告
在閱讀安全注意事項之前,請勿使用此模組。這樣做可能會導致虛假的安全感,因為 ssl 模組的預設設定不一定適合您的應用程式。
可用性:非 WASI。
此模組在 WebAssembly 上不起作用或不可用。有關更多資訊,請參閱WebAssembly 平臺。
本節記錄了 ssl
模組中的物件和函式;有關 TLS、SSL 和證書的更多一般資訊,請讀者參考底部的“另請參閱”部分中的文件。
此模組提供一個類 ssl.SSLSocket
,該類派生自 socket.socket
型別,並提供一個類似套接字的包裝器,該包裝器還使用 SSL 對透過套接字傳輸的資料進行加密和解密。它支援其他方法,例如 getpeercert()
,用於檢索連線另一端的證書,cipher()
,用於檢索用於安全連線的密碼或 get_verified_chain()
, get_unverified_chain()
,用於檢索證書鏈。
對於更復雜的應用程式,ssl.SSLContext
類有助於管理設定和證書,然後可以透過 SSLContext.wrap_socket()
方法建立的 SSL 套接字繼承這些設定和證書。
在 3.5.3 版本中更改: 更新以支援與 OpenSSL 1.1.0 連結
在 3.6 版本中更改: OpenSSL 0.9.8、1.0.0 和 1.0.1 已棄用且不再支援。將來,ssl 模組將至少需要 OpenSSL 1.0.2 或 1.1.0。
在 3.10 版本中更改: PEP 644 已實現。ssl 模組需要 OpenSSL 1.1.1 或更高版本。
使用已棄用的常量和函式會導致棄用警告。
函式、常量和異常¶
套接字建立¶
SSLSocket
的例項必須使用 SSLContext.wrap_socket()
方法建立。輔助函式 create_default_context()
返回具有安全預設設定的新上下文。
具有預設上下文和 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())
在 localhost 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()
...
上下文建立¶
一個便捷函式有助於為常見目的建立 SSLContext
物件。
- ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)¶
返回一個新的
SSLContext
物件,該物件具有給定 *purpose* 的預設設定。這些設定由ssl
模組選擇,通常比直接呼叫SSLContext
建構函式具有更高的安全級別。cafile、capath、cadata 表示用於證書驗證的可選 CA 證書,如
SSLContext.load_verify_locations()
中所述。如果這三者都是None
,則此函式可以選擇信任系統的預設 CA 證書。這些設定是:
PROTOCOL_TLS_CLIENT
或PROTOCOL_TLS_SERVER
、OP_NO_SSLv2
和OP_NO_SSLv3
,以及不帶 RC4 和不帶未經身份驗證的密碼套件的高加密密碼套件。將SERVER_AUTH
作為 *purpose* 傳遞會將verify_mode
設定為CERT_REQUIRED
,並且要麼載入 CA 證書(當給定 *cafile*、*capath* 或 *cadata* 中的至少一個時),要麼使用SSLContext.load_default_certs()
載入預設 CA 證書。當支援
keylog_filename
並且設定了環境變數SSLKEYLOGFILE
時,create_default_context()
將啟用金鑰日誌記錄。此上下文的預設設定包括
VERIFY_X509_PARTIAL_CHAIN
和VERIFY_X509_STRICT
。這些設定使底層的 OpenSSL 實現的行為更像 RFC 5280 的符合規範的實現,但會與較舊的 X.509 證書產生少量不相容性。註解
協議、選項、密碼和其他設定可能會隨時更改為更嚴格的值,而無需事先棄用。這些值表示相容性和安全性之間的合理平衡。
如果您的應用程式需要特定的設定,則應建立一個
SSLContext
並自行應用這些設定。註解
如果您發現某些較舊的客戶端或伺服器嘗試使用此函式建立的
SSLContext
進行連線時,收到錯誤訊息“協議或密碼套件不匹配”,則可能是它們僅支援 SSL3.0,而此函式使用OP_NO_SSLv3
將其排除在外。SSL3.0 被廣泛認為是完全損壞的。如果您仍然希望繼續使用此函式但仍然允許 SSL 3.0 連線,則可以使用以下程式碼重新啟用它們ctx = ssl.create_default_context(Purpose.CLIENT_AUTH) ctx.options &= ~ssl.OP_NO_SSLv3
註解
此上下文預設啟用
VERIFY_X509_STRICT
,這可能會拒絕底層的 OpenSSL 實現原本會接受的 pre-RFC 5280 或格式錯誤的證書。雖然不建議停用此選項,但您可以使用以下程式碼停用它ctx = ssl.create_default_context() ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT
在 3.4 版本中新增。
在 3.4.4 版本中更改: 從預設密碼字串中刪除了 RC4。
在 3.6 版本中更改: 將 ChaCha20/Poly1305 新增到預設密碼字串中。
從預設密碼字串中刪除了 3DES。
在 3.8 版本中更改: 添加了對金鑰日誌記錄到
SSLKEYLOGFILE
的支援。在 3.10 版本中更改: 上下文現在使用
PROTOCOL_TLS_CLIENT
或PROTOCOL_TLS_SERVER
協議,而不是通用的PROTOCOL_TLS
。在 3.13 版本中更改: 上下文現在在其預設驗證標誌中使用
VERIFY_X509_PARTIAL_CHAIN
和VERIFY_X509_STRICT
。
異常¶
- exception ssl.SSLError¶
當底層 SSL 實現(當前由 OpenSSL 庫提供)發出錯誤訊號時引發。這表示在疊加在底層網路連線之上的更高層的加密和身份驗證層中存在一些問題。此錯誤是
OSError
的子型別。SSLError
例項的錯誤程式碼和訊息由 OpenSSL 庫提供。在 3.3 版本中更改:
SSLError
曾經是socket.error
的子型別。- library¶
一個字串助記符,用於指定發生錯誤的 OpenSSL 子模組,例如
SSL
、PEM
或X509
。可能值的範圍取決於 OpenSSL 版本。在 3.3 版本中新增。
- reason¶
一個字串助記符,用於指定發生此錯誤的原因,例如
CERTIFICATE_VERIFY_FAILED
。可能值的範圍取決於 OpenSSL 版本。在 3.3 版本中新增。
- exception ssl.SSLZeroReturnError¶
當嘗試讀取或寫入並且 SSL 連線已乾淨關閉時引發的
SSLError
的子類。請注意,這並不意味著底層的傳輸(讀取 TCP)已關閉。在 3.3 版本中新增。
- exception ssl.SSLWantReadError¶
當嘗試讀取或寫入資料時,非阻塞 SSL 套接字 引發的
SSLError
的子類,但在請求可以完成之前,需要在底層的 TCP 傳輸上接收更多資料。在 3.3 版本中新增。
- exception ssl.SSLWantWriteError¶
當嘗試讀取或寫入資料時,非阻塞 SSL 套接字 引發的
SSLError
的子類,但在請求可以完成之前,需要在底層的 TCP 傳輸上傳送更多資料。在 3.3 版本中新增。
- 異常 ssl.SSLSyscallError¶
是
SSLError
的子類,當在 SSL 套接字上嘗試執行操作時遇到系統錯誤時引發。不幸的是,沒有簡單的方法來檢查原始的 errno 編號。在 3.3 版本中新增。
- 異常 ssl.SSLCertVerificationError¶
是
SSLError
的子類,當證書驗證失敗時引發。3.7 版本新增。
- verify_code¶
表示驗證錯誤的數字錯誤程式碼。
- verify_message¶
表示驗證錯誤的人類可讀的字串。
- 異常 ssl.CertificateError¶
是
SSLCertVerificationError
的別名。在 3.7 版本中更改: 該異常現在是
SSLCertVerificationError
的別名。
隨機數生成¶
- ssl.RAND_bytes(num)¶
返回 num 個密碼學上安全的偽隨機位元組。 如果 PRNG 未使用足夠的資料進行種子初始化,或者當前 RAND 方法不支援該操作,則引發
SSLError
。RAND_status()
可用於檢查 PRNG 的狀態,RAND_add()
可用於為 PRNG 提供種子。對於幾乎所有應用程式,
os.urandom()
是更好的選擇。閱讀維基百科文章,密碼學安全的偽隨機數生成器(CSPRNG),瞭解密碼學安全生成器的要求。
在 3.3 版本中新增。
- ssl.RAND_status()¶
如果 SSL 偽隨機數生成器已使用“足夠”的隨機性進行種子初始化,則返回
True
,否則返回False
。 您可以使用ssl.RAND_egd()
和ssl.RAND_add()
來增加偽隨機數生成器的隨機性。
證書處理¶
- ssl.cert_time_to_seconds(cert_time)¶
返回自 Epoch 以來的秒數,給定一個
cert_time
字串,該字串表示證書中"%b %d %H:%M:%S %Y %Z"
strptime 格式(C 語言環境)的 “notBefore” 或 “notAfter” 日期。這是一個示例
>>> 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 版本中更改: 將輸入時間解釋為輸入字串中“GMT”時區指定的 UTC 時間。之前使用本地時區。 返回一個整數(輸入格式中沒有秒的小數部分)
- ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS_CLIENT, ca_certs=None[, timeout])¶
給定一個受 SSL 保護的伺服器的地址
addr
,以 (hostname, port-number) 對的形式,獲取伺服器的證書,並將其作為 PEM 編碼的字串返回。如果指定了ssl_version
,則使用該版本的 SSL 協議嘗試連線到伺服器。如果指定了 ca_certs ,它應該是一個包含根證書列表的檔案,其格式與SSLContext.load_verify_locations()
中 cafile 引數使用的格式相同。該呼叫將嘗試針對該組根證書驗證伺服器證書,如果驗證嘗試失敗,則該呼叫將失敗。可以使用timeout
引數指定超時。在 3.3 版本中更改: 此函式現在與 IPv6 相容。
在 3.5 版本中更改: 為了與現代伺服器實現最大相容性,預設的 ssl_version 從
PROTOCOL_SSLv3
更改為PROTOCOL_TLS
。在 3.10 版本中更改: 添加了 timeout 引數。
- ssl.DER_cert_to_PEM_cert(DER_cert_bytes)¶
給定一個以 DER 編碼的位元組 Blob 形式的證書,返回同一證書的 PEM 編碼的字串版本。
- ssl.PEM_cert_to_DER_cert(PEM_cert_string)¶
給定一個 ASCII PEM 字串形式的證書,返回該證書的 DER 編碼的位元組序列。
- ssl.get_default_verify_paths()¶
返回一個包含 OpenSSL 預設 cafile 和 capath 路徑的具名元組。 這些路徑與
SSLContext.set_default_verify_paths()
使用的路徑相同。 返回值是一個具名元組DefaultVerifyPaths
cafile
- cafile 的解析路徑,如果該檔案不存在,則為None
,capath
- capath 的解析路徑,如果該目錄不存在,則為None
,openssl_cafile_env
- 指向 cafile 的 OpenSSL 環境變數鍵,openssl_cafile
- cafile 的硬編碼路徑,openssl_capath_env
- 指向 capath 的 OpenSSL 環境變數鍵,openssl_capath
- 指向 capath 目錄的硬編碼路徑
在 3.4 版本中新增。
- ssl.enum_certificates(store_name)¶
從 Windows 系統證書儲存中檢索證書。store_name 可以是
CA
、ROOT
或MY
之一。Windows 也可能提供額外的證書儲存。該函式返回一個 (cert_bytes, encoding_type, trust) 元組的列表。encoding_type 指定 cert_bytes 的編碼。它可以是 X.509 ASN.1 資料的
x509_asn
,或者 PKCS#7 ASN.1 資料的pkcs_7_asn
。Trust 將證書的目的指定為一組 OID,或者如果證書對所有目的都可信,則精確地指定為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 版本中新增。
常量¶
所有常量現在都是
enum.IntEnum
或enum.IntFlag
集合。在版本 3.6 中新增。
- ssl.CERT_NONE¶
SSLContext.verify_mode
的可能值。除了PROTOCOL_TLS_CLIENT
之外,它是預設模式。使用客戶端套接字時,幾乎接受任何證書。驗證錯誤(例如不受信任或過期的證書)將被忽略,並且不會中止 TLS/SSL 握手。在伺服器模式下,不會向客戶端請求證書,因此客戶端不會發送任何證書以進行客戶端證書身份驗證。
請參閱下面的安全注意事項的討論。
- ssl.CERT_OPTIONAL¶
SSLContext.verify_mode
的可能值。在客戶端模式下,CERT_OPTIONAL
與CERT_REQUIRED
具有相同的含義。建議對客戶端套接字使用CERT_REQUIRED
。在伺服器模式下,會向客戶端傳送客戶端證書請求。客戶端可以忽略該請求或傳送證書以執行 TLS 客戶端證書身份驗證。如果客戶端選擇傳送證書,則會對其進行驗證。任何驗證錯誤都會立即中止 TLS 握手。
使用此設定需要將有效的 CA 證書集傳遞給
SSLContext.load_verify_locations()
。
- ssl.CERT_REQUIRED¶
SSLContext.verify_mode
的可能值。在此模式下,套接字連線的另一端需要證書;如果沒有提供證書,或者其驗證失敗,則會引發SSLError
。此模式不足以在客戶端模式下驗證證書,因為它不匹配主機名。check_hostname
也必須啟用以驗證證書的真實性。PROTOCOL_TLS_CLIENT
預設使用CERT_REQUIRED
並啟用check_hostname
。使用伺服器套接字時,此模式提供強制性的 TLS 客戶端證書身份驗證。客戶端證書請求將傳送到客戶端,並且客戶端必須提供有效且受信任的證書。
使用此設定需要將有效的 CA 證書集傳遞給
SSLContext.load_verify_locations()
。
- class ssl.VerifyMode¶
CERT_* 常量的
enum.IntEnum
集合。在版本 3.6 中新增。
- ssl.VERIFY_DEFAULT¶
SSLContext.verify_flags
的可能值。在此模式下,不會檢查證書吊銷列表 (CRL)。預設情況下,OpenSSL 既不要求也不驗證 CRL。在 3.4 版本中新增。
- ssl.VERIFY_CRL_CHECK_LEAF¶
SSLContext.verify_flags
的可能值。在此模式下,僅檢查對等證書,而不檢查任何中間 CA 證書。該模式需要一個由對等證書的頒發者(其直接上級 CA)簽名的有效 CRL。如果沒有使用SSLContext.load_verify_locations
載入適當的 CRL,則驗證將失敗。在 3.4 版本中新增。
- ssl.VERIFY_CRL_CHECK_CHAIN¶
SSLContext.verify_flags
的可能值。在此模式下,將檢查對等證書鏈中所有證書的 CRL。在 3.4 版本中新增。
- ssl.VERIFY_X509_STRICT¶
SSLContext.verify_flags
的可能值,用於停用針對損壞的 X.509 證書的解決方法。在 3.4 版本中新增。
- ssl.VERIFY_ALLOW_PROXY_CERTS¶
SSLContext.verify_flags
的可能值,用於啟用代理證書驗證。在版本 3.10 中新增。
- ssl.VERIFY_X509_TRUSTED_FIRST¶
SSLContext.verify_flags
的可能值。它指示 OpenSSL 在構建信任鏈以驗證證書時優先使用受信任的證書。預設情況下啟用此標誌。在版本 3.4.4 中新增。
- ssl.VERIFY_X509_PARTIAL_CHAIN¶
SSLContext.verify_flags
的可能值。它指示 OpenSSL 接受信任儲存中的中間 CA 作為信任錨,就像自簽名根 CA 證書一樣。這使得可以信任由中間 CA 頒發的證書,而無需信任其上級根 CA。在版本 3.10 中新增。
- class ssl.VerifyFlags¶
VERIFY_* 常量的
enum.IntFlag
集合。在版本 3.6 中新增。
- ssl.PROTOCOL_TLS¶
選擇客戶端和伺服器都支援的最高協議版本。儘管名稱如此,此選項可以選擇“SSL”和“TLS”協議。
在版本 3.6 中新增。
自 3.10 版本起已棄用: TLS 客戶端和伺服器需要不同的預設設定以進行安全通訊。通用的 TLS 協議常量已被棄用,取而代之的是
PROTOCOL_TLS_CLIENT
和PROTOCOL_TLS_SERVER
。
- ssl.PROTOCOL_TLS_CLIENT¶
自動協商客戶端和伺服器都支援的最高協議版本,並配置上下文客戶端連線。該協議預設啟用
CERT_REQUIRED
和check_hostname
。在版本 3.6 中新增。
- ssl.PROTOCOL_TLS_SERVER¶
自動協商客戶端和伺服器都支援的最高協議版本,並配置上下文伺服器端連線。
在版本 3.6 中新增。
- ssl.PROTOCOL_SSLv23¶
是
PROTOCOL_TLS
的別名。自 3.6 版本起已棄用: 請改用
PROTOCOL_TLS
。
- ssl.PROTOCOL_SSLv3¶
選擇 SSL 版本 3 作為通道加密協議。
如果 OpenSSL 是使用
no-ssl3
選項編譯的,則此協議不可用。警告
SSL 版本 3 不安全。強烈建議不要使用它。
自 3.6 版本起已棄用: OpenSSL 已棄用所有特定版本的協議。請改用預設協議
PROTOCOL_TLS_SERVER
或PROTOCOL_TLS_CLIENT
,並使用SSLContext.minimum_version
和SSLContext.maximum_version
。
- ssl.PROTOCOL_TLSv1¶
選擇 TLS 版本 1.0 作為通道加密協議。
自 3.6 版本起已棄用: OpenSSL 已棄用所有特定版本的協議。
- ssl.PROTOCOL_TLSv1_1¶
選擇 TLS 版本 1.1 作為通道加密協議。僅在 openssl 版本 1.0.1+ 中可用。
在 3.4 版本中新增。
自 3.6 版本起已棄用: OpenSSL 已棄用所有特定版本的協議。
- ssl.PROTOCOL_TLSv1_2¶
選擇 TLS 版本 1.2 作為通道加密協議。僅在 openssl 版本 1.0.1+ 中可用。
在 3.4 版本中新增。
自 3.6 版本起已棄用: OpenSSL 已棄用所有特定版本的協議。
- ssl.OP_ALL¶
啟用對其他 SSL 實現中存在的各種錯誤的解決方法。預設情況下會設定此選項。它不一定會設定與 OpenSSL 的
SSL_OP_ALL
常量相同的標誌。3.2 版本中新增。
- ssl.OP_NO_SSLv2¶
阻止 SSLv2 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 SSLv2 作為協議版本。3.2 版本中新增。
自 3.6 版本起已棄用: SSLv2 已被棄用
- ssl.OP_NO_SSLv3¶
阻止 SSLv3 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 SSLv3 作為協議版本。3.2 版本中新增。
自 3.6 版本起已棄用: SSLv3 已被棄用
- ssl.OP_NO_TLSv1¶
阻止 TLSv1 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 TLSv1 作為協議版本。3.2 版本中新增。
自 3.7 版本起已棄用: 自 OpenSSL 1.1.0 起,該選項已被棄用,請改用新的
SSLContext.minimum_version
和SSLContext.maximum_version
。
- ssl.OP_NO_TLSv1_1¶
阻止 TLSv1.1 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 TLSv1.1 作為協議版本。僅在 openssl 版本 1.0.1+ 中可用。在 3.4 版本中新增。
自 3.7 版本起已棄用: 自 OpenSSL 1.1.0 起,該選項已被棄用。
- ssl.OP_NO_TLSv1_2¶
阻止 TLSv1.2 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 TLSv1.2 作為協議版本。僅在 openssl 版本 1.0.1+ 中可用。在 3.4 版本中新增。
自 3.7 版本起已棄用: 自 OpenSSL 1.1.0 起,該選項已被棄用。
- ssl.OP_NO_TLSv1_3¶
阻止 TLSv1.3 連線。此選項僅適用於
PROTOCOL_TLS
。它阻止對等方選擇 TLSv1.3 作為協議版本。TLS 1.3 在 OpenSSL 1.1.1 或更高版本中可用。當 Python 是針對舊版本的 OpenSSL 編譯的時,該標誌預設為 0。3.6.3 版本中新增。
自 3.7 版本起已棄用: 自 OpenSSL 1.1.0 起,該選項已被棄用。為了向後相容 OpenSSL 1.0.2,它被新增到 2.7.15 和 3.6.3 中。
- ssl.OP_NO_RENEGOTIATION¶
停用 TLSv1.2 及更早版本中的所有重新協商。不傳送 HelloRequest 訊息,並忽略透過 ClientHello 發起的重新協商請求。
此選項僅適用於 OpenSSL 1.1.0h 及更高版本。
3.7 版本新增。
- ssl.OP_CIPHER_SERVER_PREFERENCE¶
使用伺服器的密碼排序偏好,而不是客戶端的。此選項對客戶端套接字和 SSLv2 伺服器套接字無效。
在 3.3 版本中新增。
- ssl.OP_SINGLE_DH_USE¶
阻止對不同的 SSL 會話重複使用相同的 DH 金鑰。這提高了前向安全性,但需要更多的計算資源。此選項僅適用於伺服器套接字。
在 3.3 版本中新增。
- ssl.OP_SINGLE_ECDH_USE¶
阻止對不同的 SSL 會話重複使用相同的 ECDH 金鑰。這提高了前向安全性,但需要更多的計算資源。此選項僅適用於伺服器套接字。
在 3.3 版本中新增。
- ssl.OP_ENABLE_MIDDLEBOX_COMPAT¶
在 TLS 1.3 握手過程中傳送虛擬的更改密碼規範 (CCS) 訊息,使 TLS 1.3 連線看起來更像 TLS 1.2 連線。
此選項僅適用於 OpenSSL 1.1.1 及更高版本。
3.8 版本中新增。
- ssl.OP_NO_COMPRESSION¶
停用 SSL 通道上的壓縮。如果應用程式協議支援自己的壓縮方案,這將非常有用。
在 3.3 版本中新增。
- class ssl.Options¶
enum.IntFlag
OP_* 常量的集合。
- ssl.OP_NO_TICKET¶
阻止客戶端請求會話票證。
在版本 3.6 中新增。
- ssl.OP_IGNORE_UNEXPECTED_EOF¶
忽略 TLS 連線的意外關閉。
此選項僅適用於 OpenSSL 3.0.0 及更高版本。
在版本 3.10 中新增。
- ssl.OP_ENABLE_KTLS¶
啟用核心 TLS 的使用。要利用該功能,OpenSSL 必須已編譯支援該功能,並且協商的密碼套件和擴充套件必須受其支援(支援的列表可能因平臺和核心版本而異)。
請注意,在啟用了核心 TLS 的情況下,某些加密操作直接由核心執行,而不是透過任何可用的 OpenSSL 提供程式執行。如果例如應用程式要求所有加密操作都由 FIPS 提供程式執行,這可能是不可取的。
此選項僅適用於 OpenSSL 3.0.0 及更高版本。
3.12 版本中新增。
- ssl.OP_LEGACY_SERVER_CONNECT¶
僅允許 OpenSSL 和未修補的伺服器之間的舊式不安全重新協商。
3.12 版本中新增。
- ssl.HAS_NEVER_CHECK_COMMON_NAME¶
OpenSSL 庫是否內建支援不檢查主題通用名稱,並且
SSLContext.hostname_checks_common_name
是否可寫。3.7 版本新增。
- ssl.HAS_ECDH¶
OpenSSL 庫是否內建支援基於橢圓曲線的 Diffie-Hellman 金鑰交換。除非分發者明確停用此功能,否則應為 True。
在 3.3 版本中新增。
- ssl.HAS_NPN¶
OpenSSL 庫是否內建支援 下一協議協商,如 應用層協議協商 中所述。如果為 True,您可以使用
SSLContext.set_npn_protocols()
方法來宣告您想要支援的協議。在 3.3 版本中新增。
- ssl.HAS_SSLv2¶
OpenSSL 庫是否內建支援 SSL 2.0 協議。
3.7 版本新增。
- ssl.HAS_SSLv3¶
OpenSSL 庫是否內建支援 SSL 3.0 協議。
3.7 版本新增。
- ssl.HAS_TLSv1¶
OpenSSL 庫是否內建支援 TLS 1.0 協議。
3.7 版本新增。
- ssl.HAS_TLSv1_1¶
OpenSSL 庫是否內建支援 TLS 1.1 協議。
3.7 版本新增。
- ssl.HAS_TLSv1_2¶
OpenSSL 庫是否內建支援 TLS 1.2 協議。
3.7 版本新增。
- ssl.HAS_TLSv1_3¶
OpenSSL 庫是否內建支援 TLS 1.3 協議。
3.7 版本新增。
- ssl.HAS_PSK¶
OpenSSL 庫是否內建支援 TLS-PSK。
在 3.13 版本中新增。
- ssl.CHANNEL_BINDING_TYPES¶
支援的 TLS 通道繫結型別列表。此列表中的字串可以用作
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 庫的版本資訊的五個整數的元組
>>> ssl.OPENSSL_VERSION_INFO (1, 0, 2, 11, 15)
3.2 版本中新增。
- ssl.OPENSSL_VERSION_NUMBER¶
OpenSSL 庫的原始版本號,以單個整數表示
>>> 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 和其他規範的警報描述。IANA TLS 警報登錄檔包含此列表和對其含義進行定義的 RFC 的引用。
用作
SSLContext.set_servername_callback()
中回撥函式的返回值。在 3.4 版本中新增。
- class ssl.AlertDescription¶
enum.IntEnum
ALERT_DESCRIPTION_* 常量的集合。在版本 3.6 中新增。
- Purpose.SERVER_AUTH¶
create_default_context()
和SSLContext.load_default_certs()
的選項。此值表示上下文可用於驗證 Web 伺服器(因此,它將用於建立客戶端套接字)。在 3.4 版本中新增。
- Purpose.CLIENT_AUTH¶
create_default_context()
和SSLContext.load_default_certs()
的選項。此值表示上下文可用於驗證 Web 客戶端(因此,它將用於建立伺服器端套接字)。在 3.4 版本中新增。
- class ssl.SSLErrorNumber¶
enum.IntEnum
SSL_ERROR_* 常量的集合。在版本 3.6 中新增。
- class ssl.TLSVersion¶
enum.IntEnum
SSLContext.maximum_version
和SSLContext.minimum_version
的 SSL 和 TLS 版本集合。3.7 版本新增。
- TLSVersion.MINIMUM_SUPPORTED¶
- TLSVersion.MAXIMUM_SUPPORTED¶
支援的最小或最大 SSL 或 TLS 版本。這些是魔法常量。它們的值不反映最低和最高可用的 TLS/SSL 版本。
- TLSVersion.SSLv3¶
- TLSVersion.TLSv1¶
- TLSVersion.TLSv1_1¶
- TLSVersion.TLSv1_2¶
- TLSVersion.TLSv1_3¶
SSL 3.0 到 TLS 1.3。
自 3.10 版本起已棄用: 除了
TLSVersion.TLSv1_2
和TLSVersion.TLSv1_3
之外的所有TLSVersion
成員都已棄用。
SSL 套接字¶
- class ssl.SSLSocket(socket.socket)¶
SSL 套接字提供 套接字物件 的以下方法
recv()
,recv_into()
(但傳遞非零的flags
引數是不允許的)sendfile()
(但是os.sendfile
僅用於純文字套接字,否則將使用send()
)
然而,由於 SSL(和 TLS)協議在 TCP 之上擁有自己的幀結構,SSL 套接字抽象在某些方面可能與普通作業系統級別套接字的規範有所不同。尤其請參閱 關於非阻塞套接字的說明。
SSLSocket
的例項必須使用SSLContext.wrap_socket()
方法建立。3.5 版本更改: 添加了
sendfile()
方法。3.5 版本更改:
shutdown()
不再在每次接收或傳送位元組時重置套接字超時。套接字超時現在是關閉的最大總持續時間。3.6 版本起已棄用: 不推薦直接建立
SSLSocket
例項,請使用SSLContext.wrap_socket()
來包裝套接字。3.7 版本更改:
SSLSocket
例項必須使用wrap_socket()
建立。在早期版本中,可以直接建立例項。但這從未被記錄或官方支援。3.10 版本更改: Python 現在在內部使用
SSL_read_ex
和SSL_write_ex
。這些函式支援讀取和寫入大於 2 GB 的資料。寫入零長度的資料不再會因協議違規錯誤而失敗。
SSL 套接字還具有以下附加方法和屬性
- SSLSocket.read(len=1024, buffer=None)¶
從 SSL 套接字讀取最多 len 位元組的資料,並將結果作為
bytes
例項返回。如果指定了 buffer,則改為讀取到緩衝區中,並返回讀取的位元組數。如果套接字是 非阻塞的 並且讀取會阻塞,則引發
SSLWantReadError
或SSLWantWriteError
。由於隨時可能進行重新協商,因此呼叫
read()
也可能導致寫入操作。3.5 版本更改: 套接字超時不再在每次接收或傳送位元組時重置。套接字超時現在是讀取最多 len 位元組的最大總持續時間。
3.6 版本起已棄用: 使用
recv()
而不是read()
。
- SSLSocket.write(buf)¶
將 buf 寫入 SSL 套接字,並返回寫入的位元組數。 buf 引數必須是支援緩衝區介面的物件。
如果套接字是 非阻塞的 並且寫入會阻塞,則引發
SSLWantReadError
或SSLWantWriteError
。由於隨時可能進行重新協商,因此呼叫
write()
也可能導致讀取操作。3.5 版本更改: 套接字超時不再在每次接收或傳送位元組時重置。套接字超時現在是寫入 buf 的最大總持續時間。
3.6 版本起已棄用: 使用
send()
而不是write()
。
註解
read()
和 write()
方法是底層方法,用於讀取和寫入未加密的應用程式級別資料,並將其解密/加密為加密的線路級別資料。這些方法需要活動的 SSL 連線,即已完成握手且未呼叫 SSLSocket.unwrap()
。
- SSLSocket.do_handshake()¶
執行 SSL 設定握手。
3.4 版本更改: 當套接字的
context
的check_hostname
屬性為 true 時,握手方法還會執行match_hostname()
。3.5 版本更改: 套接字超時不再在每次接收或傳送位元組時重置。套接字超時現在是握手的最大總持續時間。
3.7 版本更改: 主機名或 IP 地址在握手期間由 OpenSSL 匹配。不再使用函式
match_hostname()
。如果 OpenSSL 拒絕主機名或 IP 地址,握手會提前中止,並向對等方傳送 TLS 警報訊息。
- SSLSocket.getpeercert(binary_form=False)¶
如果連線另一端的對等方沒有證書,則返回
None
。如果尚未完成 SSL 握手,則引發ValueError
。如果
binary_form
引數為False
,並且從對等方收到證書,則此方法返回一個dict
例項。 如果證書未經過驗證,則字典為空。如果證書經過驗證,則它返回一個包含多個鍵的字典,其中包括subject
(頒發證書的主體)和issuer
(頒發證書的主體)。如果證書包含 *Subject Alternative Name* 擴充套件的例項(請參閱RFC 3280),則字典中還會有一個subjectAltName
鍵。subject
和issuer
欄位是元組,其中包含證書資料結構中各自欄位給出的相對可分辨名稱 (RDN) 序列,每個 RDN 都是名稱-值對的序列。這是一個真實的示例{'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}
如果
binary_form
引數為True
,並且提供了證書,則此方法將以位元組序列形式返回整個證書的 DER 編碼形式,或者如果對等方未提供證書,則返回None
。對等方是否提供證書取決於 SSL 套接字的角色對於客戶端 SSL 套接字,無論是否需要驗證,伺服器都將始終提供證書;
對於伺服器 SSL 套接字,僅當伺服器請求時,客戶端才會提供證書;因此,如果您使用
CERT_NONE
(而不是CERT_OPTIONAL
或CERT_REQUIRED
),getpeercert()
將返回None
。
另請參閱
SSLContext.check_hostname
。3.2 版本更改: 返回的字典包含其他項,如
issuer
和notBefore
。3.4 版本更改: 當握手未完成時,將引發
ValueError
。返回的字典包含其他 X509v3 擴充套件項,如crlDistributionPoints
、caIssuers
和OCSP
URI。3.9 版本更改: IPv6 地址字串不再包含尾隨換行符。
- SSLSocket.get_verified_chain()¶
以 DER 編碼的位元組列表形式返回 SSL 通道另一端提供的已驗證證書鏈。如果停用證書驗證,則此方法的作用與
get_unverified_chain()
相同。在 3.13 版本中新增。
- SSLSocket.get_unverified_chain()¶
以 DER 編碼的位元組列表形式返回 SSL 通道另一端提供的原始證書鏈。
在 3.13 版本中新增。
- SSLSocket.cipher()¶
返回一個三值元組,其中包含正在使用的密碼的名稱、定義其使用的 SSL 協議的版本以及正在使用的秘密位數。 如果尚未建立連線,則返回
None
。
返回客戶端和伺服器中都可用的密碼列表。 返回的列表的每個條目都是一個三值元組,其中包含密碼的名稱、定義其使用的 SSL 協議的版本以及密碼使用的秘密位數。 如果未建立連線或套接字是客戶端套接字,則
shared_ciphers()
返回None
。在 3.5 版本中新增。
- SSLSocket.compression()¶
以字串形式返回正在使用的壓縮演算法,如果連線未壓縮,則返回
None
。如果更高級別的協議支援其自身的壓縮機制,則可以使用
OP_NO_COMPRESSION
來停用 SSL 級別的壓縮。在 3.3 版本中新增。
- SSLSocket.get_channel_binding(cb_type='tls-unique')¶
獲取當前連線的通道繫結資料,作為位元組物件。如果未連線或握手尚未完成,則返回
None
。cb_type 引數允許選擇所需的通道繫結型別。 有效的通道繫結型別在
CHANNEL_BINDING_TYPES
列表中列出。目前僅支援由 RFC 5929 定義的 'tls-unique' 通道繫結。 如果請求不支援的通道繫結型別,則會引發ValueError
。在 3.3 版本中新增。
- SSLSocket.selected_alpn_protocol()¶
返回在 TLS 握手期間選擇的協議。 如果未呼叫
SSLContext.set_alpn_protocols()
,如果另一方不支援 ALPN,如果此套接字不支援任何客戶端的提議協議,或者如果尚未發生握手,則返回None
。在 3.5 版本中新增。
- SSLSocket.selected_npn_protocol()¶
返回在 TLS/SSL 握手期間選擇的更高級別協議。 如果未呼叫
SSLContext.set_npn_protocols()
,或者如果另一方不支援 NPN,或者如果握手尚未發生,則這將返回None
。在 3.3 版本中新增。
自 3.10 版本棄用: NPN 已被 ALPN 取代
- SSLSocket.unwrap()¶
執行 SSL 關閉握手,這將從底層套接字中刪除 TLS 層,並返回底層套接字物件。這可用於從連線上的加密操作轉換為未加密操作。 返回的套接字應始終用於與連線的另一端進行進一步通訊,而不是原始套接字。
- SSLSocket.verify_client_post_handshake()¶
請求 TLS 1.3 客戶端進行握手後身份驗證 (PHA)。 PHA 只能在初始 TLS 握手後,從伺服器端套接字為 TLS 1.3 連線啟動,並且在雙方都啟用了 PHA,請參閱
SSLContext.post_handshake_auth
。該方法不會立即執行證書交換。伺服器端在下一個寫入事件期間傳送 CertificateRequest,並期望客戶端在下一個讀取事件中以證書響應。
如果不滿足任何前提條件(例如,不是 TLS 1.3,未啟用 PHA),則會引發
SSLError
。註解
僅在啟用 OpenSSL 1.1.1 和 TLS 1.3 時可用。 如果不支援 TLS 1.3,則該方法會引發
NotImplementedError
。3.8 版本中新增。
- SSLSocket.version()¶
返回連線協商的實際 SSL 協議版本字串,如果沒有建立安全連線,則返回
None
。截至本文撰寫時,可能的返回值包括"SSLv2"
、"SSLv3"
、"TLSv1"
、"TLSv1.1"
和"TLSv1.2"
。較新的 OpenSSL 版本可能會定義更多的返回值。在 3.5 版本中新增。
- SSLSocket.pending()¶
返回連線上可用於讀取的、已解密的位元組數。
- SSLSocket.context¶
此 SSL 套接字所繫結的
SSLContext
物件。3.2 版本中新增。
- SSLSocket.server_side¶
一個布林值,對於伺服器端套接字為
True
,對於客戶端套接字為False
。3.2 版本中新增。
- SSLSocket.server_hostname¶
伺服器的主機名:
str
型別,或者對於伺服器端套接字或如果建構函式中未指定主機名,則為None
。3.2 版本中新增。
3.7 版本更改: 該屬性現在始終是 ASCII 文字。當
server_hostname
是國際化域名 (IDN) 時,此屬性現在儲存 A-label 形式 ("xn--pythn-mua.org"
),而不是 U-label 形式 ("pythön.org"
)。
- SSLSocket.session¶
此 SSL 連線的
SSLSession
。會話在 TLS 握手執行後可用於客戶端和伺服器端套接字。對於客戶端套接字,可以在呼叫do_handshake()
之前設定會話,以重用會話。在版本 3.6 中新增。
- SSLSocket.session_reused¶
在版本 3.6 中新增。
SSL 上下文¶
3.2 版本中新增。
SSL 上下文儲存比單個 SSL 連線更持久的各種資料,例如 SSL 配置選項、證書和私鑰。它還管理伺服器端套接字的 SSL 會話快取,以便加快來自同一客戶端的重複連線。
- class ssl.SSLContext(protocol=None)¶
建立一個新的 SSL 上下文。您可以傳遞 protocol,它必須是此模組中定義的
PROTOCOL_*
常量之一。該引數指定要使用的 SSL 協議的版本。通常,伺服器選擇特定的協議版本,客戶端必須適應伺服器的選擇。大多數版本與其他版本不相容。如果未指定,則預設值為PROTOCOL_TLS
;它與其他版本提供最大的相容性。下表顯示了客戶端(在側面)中的哪些版本可以連線到伺服器(在頂部)中的哪些版本
客戶端 / 伺服器
SSLv2
SSLv3
TLS [3]
TLSv1
TLSv1.1
TLSv1.2
SSLv2
是
否
否 [1]
否
否
否
SSLv3
否
是
否 [2]
否
否
否
TLS (SSLv23) [3]
否 [1]
否 [2]
是
是
是
是
TLSv1
否
否
是
是
否
否
TLSv1.1
否
否
是
否
是
否
TLSv1.2
否
否
是
否
否
是
腳註
另請參見
create_default_context()
讓ssl
模組為給定的目的選擇安全設定。3.6 版本更改: 上下文使用安全的預設值建立。選項
OP_NO_COMPRESSION
、OP_CIPHER_SERVER_PREFERENCE
、OP_SINGLE_DH_USE
、OP_SINGLE_ECDH_USE
、OP_NO_SSLv2
和OP_NO_SSLv3
(PROTOCOL_SSLv3
除外)預設設定。初始密碼套件列表僅包含HIGH
密碼,不包含NULL
密碼,也不包含MD5
密碼。3.10 版本起已棄用: 不帶協議引數的
SSLContext
已棄用。上下文類將來將需要PROTOCOL_TLS_CLIENT
或PROTOCOL_TLS_SERVER
協議。3.10 版本更改: 預設密碼套件現在僅包含具有前向保密和安全級別 2 的安全 AES 和 ChaCha20 密碼。禁止使用少於 2048 位的 RSA 和 DH 金鑰以及少於 224 位的 ECC 金鑰。
PROTOCOL_TLS
、PROTOCOL_TLS_CLIENT
和PROTOCOL_TLS_SERVER
使用 TLS 1.2 作為最低 TLS 版本。註解
SSLContext
一旦被連線使用,僅支援有限的變動。允許向內部信任儲存新增新證書,但更改密碼、驗證設定或 mTLS 證書可能會導致意外行為。註解
SSLContext
旨在被多個連線共享和使用。因此,只要在被連線使用後不重新配置,它就是執行緒安全的。
SSLContext
物件具有以下方法和屬性
- SSLContext.cert_store_stats()¶
獲取關於已載入的 X.509 證書數量、標記為 CA 證書的 X.509 證書計數以及證書吊銷列表的統計資訊,以字典形式返回。
一個包含一個 CA 證書和一個其他證書的上下文示例
>>> context.cert_store_stats() {'crl': 0, 'x509_ca': 1, 'x509': 2}
在 3.4 版本中新增。
- SSLContext.load_cert_chain(certfile, keyfile=None, password=None)¶
載入私鑰和對應的證書。certfile 字串必須是 PEM 格式的單個檔案的路徑,其中包含證書以及建立證書真實性所需的任意數量的 CA 證書。如果存在 keyfile 字串,則必須指向包含私鑰的檔案。否則,私鑰也將從 certfile 中獲取。有關證書如何儲存在 certfile 中的更多資訊,請參閱 證書 的討論。
password 引數可以是一個用於獲取解密私鑰的密碼的函式。只有當私鑰被加密且需要密碼時才會呼叫它。它將被無引數呼叫,並應返回字串、位元組或位元組陣列。如果返回值是字串,則在用於解密金鑰之前,它將被編碼為 UTF-8。或者,可以直接將字串、位元組或位元組陣列值作為 password 引數提供。如果私鑰未加密且不需要密碼,則會忽略該引數。
如果未指定 password 引數且需要密碼,則將使用 OpenSSL 的內建密碼提示機制來互動式地提示使用者輸入密碼。
如果私鑰與證書不匹配,則會引發
SSLError
。3.3 版本更改: 新增可選引數 password。
- SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)¶
從預設位置載入一組預設的“證書頒發機構”(CA)證書。在 Windows 上,它從
CA
和ROOT
系統儲存中載入 CA 證書。在所有系統上,它都會呼叫SSLContext.set_default_verify_paths()
。將來,該方法也可能會從其他位置載入 CA 證書。purpose 標誌指定載入哪種 CA 證書。預設設定
Purpose.SERVER_AUTH
載入標記並信任用於 TLS Web 伺服器身份驗證(客戶端套接字)的證書。Purpose.CLIENT_AUTH
載入用於伺服器端客戶端證書驗證的 CA 證書。在 3.4 版本中新增。
- SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)¶
載入一組“證書頒發機構”(CA)證書,用於在
verify_mode
不是CERT_NONE
時驗證其他對等方的證書。必須至少指定 cafile 或 capath 之一。此方法還可以載入 PEM 或 DER 格式的證書吊銷列表(CRL)。為了使用 CRL,必須正確配置
SSLContext.verify_flags
。cafile 字串(如果存在)是 PEM 格式的串聯 CA 證書檔案的路徑。有關如何在此檔案中排列證書的更多資訊,請參閱 證書 的討論。
capath 字串(如果存在)是包含多個 PEM 格式的 CA 證書的目錄的路徑,遵循 OpenSSL 特定佈局。
cadata 物件(如果存在)是一個或多個 PEM 編碼證書的 ASCII 字串,或者是一個 DER 編碼證書的 類位元組物件。與 capath 類似,PEM 編碼證書周圍的額外行將被忽略,但必須至少存在一個證書。
3.4 版本更改: 新增可選引數 cadata
- SSLContext.get_ca_certs(binary_form=False)¶
獲取已載入的“證書頒發機構”(CA)證書的列表。如果
binary_form
引數是False
,則每個列表條目都是一個類似於SSLSocket.getpeercert()
輸出的字典。否則,該方法返回 DER 編碼的證書列表。返回的列表不包含來自 capath 的證書,除非 SSL 連線請求並載入了證書。註解
除非 capath 目錄中的證書至少使用過一次,否則不會載入它們。
在 3.4 版本中新增。
- SSLContext.get_ciphers()¶
獲取已啟用的密碼列表。該列表按密碼優先順序排序。請參閱
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 庫時定義的 檔案系統路徑載入一組預設的“證書頒發機構”(CA)證書。不幸的是,沒有簡單的方法來知道此方法是否成功:如果沒有找到任何證書,則不會返回任何錯誤。但是,當 OpenSSL 庫作為作業系統的一部分提供時,它很可能已正確配置。
- SSLContext.set_ciphers(ciphers)¶
設定使用此上下文建立的套接字的可用密碼。它應該是 OpenSSL 密碼列表格式的字串。如果無法選擇任何密碼(因為編譯時選項或其他配置禁止使用所有指定的密碼),則會引發
SSLError
。
- SSLContext.set_alpn_protocols(protocols)¶
指定套接字在 SSL/TLS 握手期間應通告的協議。它應該是一個 ASCII 字串列表,例如
['http/1.1', 'spdy/2']
,按優先順序排序。協議的選擇將在握手期間發生,並將按照 RFC 7301 進行。成功握手後,SSLSocket.selected_alpn_protocol()
方法將返回商定的協議。如果
HAS_ALPN
為False
,則此方法將引發NotImplementedError
。在 3.5 版本中新增。
- SSLContext.set_npn_protocols(protocols)¶
指定套接字在 SSL/TLS 握手期間應通告的協議。它應該是一個字串列表,例如
['http/1.1', 'spdy/2']
,按優先順序排序。協議的選擇將在握手期間發生,並將根據應用層協議協商進行。成功握手後,SSLSocket.selected_npn_protocol()
方法將返回商定的協議。如果
HAS_NPN
為False
,則此方法將引發NotImplementedError
。在 3.3 版本中新增。
自 3.10 版本棄用: NPN 已被 ALPN 取代
- SSLContext.sni_callback¶
註冊一個回撥函式,該函式將在 TLS 客戶端指定伺服器名稱指示時,在 SSL/TLS 伺服器接收到 TLS 客戶端 Hello 握手訊息後被呼叫。伺服器名稱指示機制在 RFC 6066 第 3 節 - 伺服器名稱指示中指定。
每個
SSLContext
只能設定一個回撥。如果 sni_callback 設定為None
,則停用回撥。隨後呼叫此函式將停用之前註冊的回撥。回撥函式將使用三個引數呼叫;第一個是
ssl.SSLSocket
,第二個是一個字串,表示客戶端打算通訊的伺服器名稱(如果 TLS 客戶端 Hello 不包含伺服器名稱,則為None
),第三個引數是原始的SSLContext
。伺服器名稱引數是文字。對於國際化域名,伺服器名稱是 IDN A 標籤("xn--pythn-mua.org"
)。此回撥的典型用法是將
ssl.SSLSocket
的SSLSocket.context
屬性更改為SSLContext
型別的新物件,該物件表示與伺服器名稱匹配的證書鏈。由於 TLS 連線的早期協商階段,只有有限的方法和屬性可用,例如
SSLSocket.selected_alpn_protocol()
和SSLSocket.context
。SSLSocket.getpeercert()
、SSLSocket.get_verified_chain()
、SSLSocket.get_unverified_chain()
、SSLSocket.cipher()
和SSLSocket.compression()
方法要求 TLS 連線已超出 TLS 客戶端 Hello 階段,因此不會返回有意義的值,也不能安全地呼叫它們。sni_callback 函式必須返回
None
以允許 TLS 協商繼續。如果需要 TLS 失敗,則可以返回常量ALERT_DESCRIPTION_*
。其他返回值將導致 TLS 致命錯誤,並返回ALERT_DESCRIPTION_INTERNAL_ERROR
。如果從 sni_callback 函式引發異常,則 TLS 連線將以致命的 TLS 警報訊息
ALERT_DESCRIPTION_HANDSHAKE_FAILURE
終止。如果 OpenSSL 庫在構建時定義了 OPENSSL_NO_TLSEXT,則此方法將引發
NotImplementedError
。3.7 版本新增。
- SSLContext.set_servername_callback(server_name_callback)¶
這是一個為保持向後相容性而保留的舊版 API。如果可能,您應該改用
sni_callback
。給定的 server_name_callback 與 sni_callback 類似,不同之處在於,當伺服器主機名是 IDN 編碼的國際化域名時,server_name_callback 接收解碼的 U 標籤 ("pythön.org"
)。如果伺服器名稱存在解碼錯誤,則 TLS 連線將終止,並向客戶端傳送
ALERT_DESCRIPTION_INTERNAL_ERROR
致命 TLS 警報訊息。在 3.4 版本中新增。
- SSLContext.load_dh_params(dhfile)¶
載入 Diffie-Hellman (DH) 金鑰交換的金鑰生成引數。使用 DH 金鑰交換可以提高前向保密性,但會增加計算資源(伺服器和客戶端)。dhfile 引數應該是包含 PEM 格式的 DH 引數的檔案的路徑。
此設定不適用於客戶端套接字。您還可以使用
OP_SINGLE_DH_USE
選項來進一步提高安全性。在 3.3 版本中新增。
- SSLContext.set_ecdh_curve(curve_name)¶
設定基於橢圓曲線的 Diffie-Hellman (ECDH) 金鑰交換的曲線名稱。ECDH 比常規 DH 快得多,並且可以說一樣安全。curve_name 引數應該是一個字串,描述一個眾所周知的橢圓曲線,例如
prime256v1
表示廣泛支援的曲線。此設定不適用於客戶端套接字。您還可以使用
OP_SINGLE_ECDH_USE
選項來進一步提高安全性。如果
HAS_ECDH
為False
,則此方法不可用。在 3.3 版本中新增。
另請參見
- SSL/TLS 和完全前向保密
Vincent Bernat。
- SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)¶
包裝現有的 Python 套接字 sock 並返回
SSLContext.sslsocket_class
的例項(預設為SSLSocket
)。返回的 SSL 套接字繫結到上下文、其設定和證書。sock 必須是SOCK_STREAM
套接字;不支援其他套接字型別。引數
server_side
是一個布林值,用於標識此套接字需要伺服器端行為還是客戶端行為。對於客戶端套接字,上下文構造是延遲的;如果底層套接字尚未連線,則上下文構造將在套接字上呼叫
connect()
後執行。對於伺服器端套接字,如果套接字沒有遠端對等點,則假定它是一個偵聽套接字,並且伺服器端 SSL 包裝會自動在透過accept()
方法接受的客戶端連線上執行。該方法可能會引發SSLError
。在客戶端連線上,可選引數 server_hostname 指定我們正在連線的服務的 hostname。這允許單個伺服器託管具有不同證書的多個基於 SSL 的服務,這與 HTTP 虛擬主機非常相似。如果 server_side 為 true,則指定 server_hostname 將引發
ValueError
。引數
do_handshake_on_connect
指定在執行socket.connect()
後是否自動執行 SSL 握手,或者應用程式是否會透過呼叫SSLSocket.do_handshake()
方法顯式呼叫它。顯式呼叫SSLSocket.do_handshake()
使程式能夠控制握手涉及的套接字 I/O 的阻塞行為。引數
suppress_ragged_eofs
指定SSLSocket.recv()
方法應如何處理來自連線另一端的意外 EOF 訊號。如果指定為True
(預設值),則它會返回一個正常的 EOF(一個空位元組物件),以響應底層套接字引發的意外 EOF 錯誤;如果為False
,它會將異常拋回給呼叫者。session,請參見
session
。要在另一個
SSLSocket
中包裝一個SSLSocket
,請使用SSLContext.wrap_bio()
。在 3.5 版本中變更: 始終允許傳遞 server_hostname,即使 OpenSSL 沒有 SNI。
在 3.6 版本中變更: 添加了 session 引數。
在 3.7 版本中變更: 該方法返回
SSLContext.sslsocket_class
的例項,而不是硬編碼的SSLSocket
。
- SSLContext.sslsocket_class¶
SSLContext.wrap_socket()
的返回型別,預設為SSLSocket
。可以在類的例項上重寫該屬性,以便返回SSLSocket
的自定義子類。3.7 版本新增。
- SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)¶
包裝 BIO 物件 incoming 和 outgoing 並返回
SSLContext.sslobject_class
(預設為SSLObject
)的例項。SSL 例程將從傳入的 BIO 讀取輸入資料,並將資料寫入傳出的 BIO。server_side、server_hostname 和 session 引數的含義與
SSLContext.wrap_socket()
中的含義相同。在 3.6 版本中變更: 添加了 session 引數。
在 3.7 版本中變更: 該方法返回
SSLContext.sslobject_class
的例項,而不是硬編碼的SSLObject
。
- SSLContext.sslobject_class¶
SSLContext.wrap_bio()
的返回型別,預設為SSLObject
。可以在類的例項上重寫該屬性,以便返回SSLObject
的自定義子類。3.7 版本新增。
- SSLContext.session_stats()¶
獲取有關此上下文建立或管理的 SSL 會話的統計資訊。返回一個字典,其中將每個資訊片段的名稱對映到其數值。例如,這是自建立上下文以來會話快取中的總命中數和未命中數
>>> stats = context.session_stats() >>> stats['hits'], stats['misses'] (0, 0)
- SSLContext.check_hostname¶
是否在
SSLSocket.do_handshake()
中匹配對等證書的主機名。上下文的verify_mode
必須設定為CERT_OPTIONAL
或CERT_REQUIRED
,並且您必須將 server_hostname 傳遞給wrap_socket()
才能匹配主機名。啟用主機名檢查會自動將verify_mode
從CERT_NONE
設定為CERT_REQUIRED
。只要啟用主機名檢查,就無法將其設定回CERT_NONE
。PROTOCOL_TLS_CLIENT
協議預設啟用主機名檢查。對於其他協議,必須顯式啟用主機名檢查。示例
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_mode
為CERT_NONE
時,verify_mode
現在會自動更改為CERT_REQUIRED
。以前,相同的操作會因ValueError
而失敗。
- SSLContext.keylog_filename¶
每當生成或接收金鑰材料時,將 TLS 金鑰寫入金鑰日誌檔案。金鑰日誌檔案僅用於除錯目的。檔案格式由 NSS 指定,並被許多流量分析器(如 Wireshark)使用。日誌檔案以僅追加模式開啟。寫入線上程之間同步,但在程序之間不同步。
3.8 版本中新增。
- SSLContext.maximum_version¶
一個
TLSVersion
列舉成員,表示支援的最高 TLS 版本。該值預設為TLSVersion.MAXIMUM_SUPPORTED
。對於除PROTOCOL_TLS
、PROTOCOL_TLS_CLIENT
和PROTOCOL_TLS_SERVER
之外的協議,該屬性是隻讀的。屬性
maximum_version
,minimum_version
和SSLContext.options
都會影響上下文支援的 SSL 和 TLS 版本。實現不會阻止無效的組合。例如,options
中包含OP_NO_TLSv1_2
,且maximum_version
設定為TLSVersion.TLSv1_2
的上下文將無法建立 TLS 1.2 連線。3.7 版本新增。
- SSLContext.minimum_version¶
類似於
SSLContext.maximum_version
,但它是支援的最低版本,或者為TLSVersion.MINIMUM_SUPPORTED
。3.7 版本新增。
- SSLContext.num_tickets¶
控制
PROTOCOL_TLS_SERVER
上下文的 TLS 1.3 會話票證數量。此設定對 TLS 1.0 到 1.2 連線沒有影響。3.8 版本中新增。
- SSLContext.options¶
一個整數,表示在此上下文中啟用的 SSL 選項集。預設值為
OP_ALL
,但你可以透過對它們進行“或”運算來指定其他選項,例如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 版本起棄用: 自 Python 3.7 起,所有
OP_NO_SSL*
和OP_NO_TLS*
選項都已棄用。請改用SSLContext.minimum_version
和SSLContext.maximum_version
。
- SSLContext.post_handshake_auth¶
啟用 TLS 1.3 握手後客戶端身份驗證。預設情況下停用握手後身份驗證,伺服器只能在初始握手期間請求 TLS 客戶端證書。啟用後,伺服器可以在握手後的任何時間請求 TLS 客戶端證書。
在客戶端套接字上啟用時,客戶端會向伺服器發出訊號,表明它支援握手後身份驗證。
在伺服器端套接字上啟用時,
SSLContext.verify_mode
也必須設定為CERT_OPTIONAL
或CERT_REQUIRED
。實際的客戶端證書交換將延遲到呼叫SSLSocket.verify_client_post_handshake()
並執行某些 I/O 操作之後。3.8 版本中新增。
- SSLContext.protocol¶
構造上下文時選擇的協議版本。此屬性為只讀。
- SSLContext.hostname_checks_common_name¶
當缺少主題備用名稱擴充套件時,
check_hostname
是否會回退到驗證證書的主題通用名稱(預設值:true)。3.7 版本新增。
在 3.10 版本中變更: 此標誌在 1.1.1l 之前的 OpenSSL 版本中無效。Python 3.8.9、3.9.3 和 3.10 包含了對先前版本的解決方法。
- SSLContext.verify_flags¶
證書驗證操作的標誌。你可以透過對它們進行“或”運算來設定標誌,例如
VERIFY_CRL_CHECK_LEAF
。預設情況下,OpenSSL 既不要求也不驗證證書吊銷列表 (CRL)。在 3.4 版本中新增。
在 3.6 版本中變更:
SSLContext.verify_flags
返回VerifyFlags
標誌>>> ssl.create_default_context().verify_flags <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
- SSLContext.verify_mode¶
是否嘗試驗證其他對等方的證書以及如果驗證失敗該如何處理。此屬性必須是
CERT_NONE
、CERT_OPTIONAL
或CERT_REQUIRED
之一。在 3.6 版本中變更:
SSLContext.verify_mode
返回VerifyMode
列舉>>> ssl.create_default_context().verify_mode <VerifyMode.CERT_REQUIRED: 2>
- SSLContext.set_psk_client_callback(callback)¶
在客戶端連線上啟用 TLS-PSK(預共享金鑰)身份驗證。
一般來說,應該優先選擇基於證書的身份驗證,而不是此方法。
引數
callback
是一個可呼叫物件,其簽名如下:def callback(hint: str | None) -> tuple[str | None, bytes]
。hint
引數是伺服器傳送的可選身份提示。返回值是一個元組,格式為 (client-identity, psk)。Client-identity 是一個可選字串,伺服器可以使用它來選擇客戶端的相應 PSK。當使用 UTF-8 編碼時,該字串必須小於或等於256
個八位位元組。PSK 是一個表示預共享金鑰的 類位元組物件。返回零長度 PSK 以拒絕連線。將
callback
設定為None
將刪除任何現有的回撥。用法示例
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE context.maximum_version = ssl.TLSVersion.TLSv1_2 context.set_ciphers('PSK') # A simple lambda: psk = bytes.fromhex('c0ffee') context.set_psk_client_callback(lambda hint: (None, psk)) # A table using the hint from the server: psk_table = { 'ServerId_1': bytes.fromhex('c0ffee'), 'ServerId_2': bytes.fromhex('facade') } def callback(hint): return 'ClientId_1', psk_table.get(hint, b'') context.set_psk_client_callback(callback)
如果
HAS_PSK
為False
,此方法將引發NotImplementedError
。在 3.13 版本中新增。
- SSLContext.set_psk_server_callback(callback, identity_hint=None)¶
在伺服器端連線上啟用 TLS-PSK(預共享金鑰)身份驗證。
一般來說,應該優先選擇基於證書的身份驗證,而不是此方法。
引數
callback
是一個可呼叫物件,其簽名如下:def callback(identity: str | None) -> bytes
。identity
引數是客戶端傳送的可選身份標識,可用於選擇相應的 PSK。返回值是一個類位元組物件,表示預共享金鑰。返回零長度的 PSK 將拒絕連線。將
callback
設定為None
將刪除任何現有的回撥。引數
identity_hint
是傳送給客戶端的可選身份提示字串。當使用 UTF-8 編碼時,該字串必須小於或等於256
個八位位元組。註解
當使用 TLS 1.3 時,
identity_hint
引數不會發送給客戶端。用法示例
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.maximum_version = ssl.TLSVersion.TLSv1_2 context.set_ciphers('PSK') # A simple lambda: psk = bytes.fromhex('c0ffee') context.set_psk_server_callback(lambda identity: psk) # A table using the identity of the client: psk_table = { 'ClientId_1': bytes.fromhex('c0ffee'), 'ClientId_2': bytes.fromhex('facade') } def callback(identity): return psk_table.get(identity, b'') context.set_psk_server_callback(callback, 'ServerId_1')
如果
HAS_PSK
為False
,此方法將引發NotImplementedError
。在 3.13 版本中新增。
證書¶
通常,證書是公鑰/私鑰系統的一部分。在這個系統中,每個主體(可能是機器、個人或組織)都被分配一個唯一的兩部分加密金鑰。金鑰的一部分是公開的,稱為公鑰;另一部分是保密的,稱為私鑰。這兩部分是相關的,如果使用其中一部分加密訊息,則可以使用另一部分解密,而且只能使用另一部分解密。
證書包含關於兩個主體的資訊。它包含一個主題的名稱和主題的公鑰。它還包含第二個主體(頒發者)的宣告,表明該主題是其聲稱的身份,並且這確實是該主題的公鑰。頒發者的宣告使用頒發者的私鑰簽名,只有頒發者知道該私鑰。但是,任何人都可以透過查詢頒發者的公鑰、使用該公鑰解密該宣告並將其與證書中的其他資訊進行比較來驗證頒發者的宣告。證書還包含關於其有效時間段的資訊。這表示為兩個欄位,稱為“notBefore”和“notAfter”。
在 Python 中使用證書時,客戶端或伺服器可以使用證書來證明自己的身份。還可以要求網路連線的另一端提供證書,並且該證書可以被驗證,以使需要此類驗證的客戶端或伺服器滿意。如果驗證失敗,連線嘗試可以設定為引發異常。驗證由底層的 OpenSSL 框架自動完成;應用程式無需關心其機制。但是,應用程式通常需要提供證書集,以允許此過程發生。
Python 使用檔案來包含證書。它們應格式化為“PEM”(請參閱RFC 1422),這是一種 base-64 編碼形式,並用標題行和頁尾行包裹。
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----
證書鏈¶
包含證書的 Python 檔案可以包含一系列證書,有時稱為證書鏈。此鏈應從“是”客戶端或伺服器的主體的特定證書開始,然後是該證書的頒發者的證書,然後是該證書的頒發者的證書,依此類推,直到獲得一個自簽名的證書,即具有相同主題和頒發者的證書,有時稱為根證書。這些證書應該只是在證書檔案中連線在一起。例如,假設我們有一個三證書鏈,從我們的伺服器證書到簽署我們伺服器證書的證書頒發機構的證書,再到頒發證書頒發機構證書的機構的根證書。
-----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 證書¶
如果要要求驗證連線另一端的證書,則需要提供一個“CA 證書”檔案,其中填充了您願意信任的每個頒發者的證書鏈。同樣,此檔案只是包含這些連線在一起的鏈。對於驗證,Python 將使用檔案中找到的第一個匹配鏈。可以透過呼叫SSLContext.load_default_certs()
來使用平臺的證書檔案,這可以透過create_default_context()
自動完成。
組合金鑰和證書¶
通常,私鑰與證書儲存在同一個檔案中;在這種情況下,只需傳遞SSLContext.load_cert_chain()
的 certfile
引數。如果私鑰與證書一起儲存,則它應該位於證書鏈中的第一個證書之前。
-----BEGIN RSA PRIVATE KEY-----
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----
自簽名證書¶
如果要建立一個提供 SSL 加密連線服務的伺服器,則需要為該服務獲取證書。有許多方法可以獲取適當的證書,例如從證書頒發機構購買一個。另一種常見做法是生成自簽名證書。最簡單的方法是使用 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
%
自簽名證書的缺點是它是自己的根證書,而且沒有其他人會在其已知(和受信任)的根證書快取中擁有它。
示例¶
測試 SSL 支援¶
要測試 Python 安裝中是否存在 SSL 支援,使用者程式碼應使用以下習慣用法:
try:
import ssl
except ImportError:
pass
else:
... # do something that requires SSL support
客戶端操作¶
此示例使用推薦的客戶端套接字安全設定(包括自動證書驗證)建立一個 SSL 上下文:
>>> context = ssl.create_default_context()
如果您希望自己調整安全設定,則可以從頭開始建立一個上下文(但請注意,您可能無法獲得正確的設定):
>>> context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")
(此程式碼段假定您的作業系統將所有 CA 證書的捆綁包放在 /etc/ssl/certs/ca-bundle.crt
中;如果不是,您將收到一個錯誤,並且必須調整位置)
PROTOCOL_TLS_CLIENT
協議配置上下文以進行證書驗證和主機名驗證。verify_mode
設定為 CERT_REQUIRED
,check_hostname
設定為 True
。所有其他協議都使用不安全的預設值建立 SSL 上下文。
當您使用上下文連線到伺服器時,CERT_REQUIRED
和 check_hostname
驗證伺服器證書:它確保伺服器證書已使用其中一個 CA 證書籤名,檢查簽名的正確性,並驗證其他屬性,例如主機名的有效性和身份。
>>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
... server_hostname="www.python.org")
>>> conn.connect(("www.python.org", 443))
然後,您可以獲取證書:
>>> cert = conn.getpeercert()
目視檢查表明該證書確實標識了所需的服務(即 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 通道已建立並且證書已驗證,您可以繼續與伺服器通訊:
>>> 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'']
請參閱下面的安全注意事項的討論。
伺服器端操作¶
對於伺服器操作,通常您需要具有伺服器證書和私鑰,每個都在一個檔案中。您將首先建立一個包含金鑰和證書的上下文,以便客戶端可以檢查您的真實性。然後,您將開啟一個套接字,將其繫結到一個埠,對其呼叫 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.example.com', 10023))
bindsocket.listen(5)
當客戶端連線時,您將對套接字呼叫 accept()
以從另一端獲取新套接字,並使用上下文的 SSLContext.wrap_socket()
方法為連線建立伺服器端 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
中讀取資料並對其執行某些操作,直到您完成客戶端的操作(或客戶端完成您的操作):
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
然後回到監聽新客戶端連線(當然,真正的伺服器可能會在單獨的執行緒中處理每個客戶端連線,或者將套接字置於 非阻塞模式 並使用事件迴圈)。
關於非阻塞套接字的說明¶
SSL 套接字在非阻塞模式下的行為與常規套接字略有不同。當使用非阻塞套接字時,您需要注意以下幾點:
如果 I/O 操作將阻塞,則大多數
SSLSocket
方法將引發SSLWantWriteError
或SSLWantReadError
,而不是BlockingIOError
。如果底層套接字上需要讀取操作,則會引發SSLWantReadError
;對於底層套接字上的寫入操作,則會引發SSLWantWriteError
。請注意,嘗試寫入 SSL 套接字可能需要首先從底層套接字讀取,而嘗試從 SSL 套接字讀取可能需要事先對底層套接字進行寫入。在 3.5 版本中更改: 在較早的 Python 版本中,
SSLSocket.send()
方法返回零,而不是引發SSLWantWriteError
或SSLWantReadError
。呼叫
select()
會告知您作業系統級別的套接字是否可以讀取(或寫入),但這並不意味著上層 SSL 層有足夠的資料。 例如,可能只到達了 SSL 幀的一部分。 因此,您必須準備好處理SSLSocket.recv()
和SSLSocket.send()
失敗的情況,並在再次呼叫select()
後重試。相反,由於 SSL 層有自己的成幀機制,SSL 套接字可能仍然有可用於讀取的資料,而
select()
並不知道。 因此,您應該首先呼叫SSLSocket.recv()
來耗盡任何潛在可用的資料,然後僅在仍然需要時阻塞在select()
呼叫上。SSL 握手本身將是非阻塞的:必須重試
SSLSocket.do_handshake()
方法,直到它成功返回。以下是使用select()
等待套接字就緒的概要while True: try: sock.do_handshake() break except ssl.SSLWantReadError: select.select([sock], [], []) except ssl.SSLWantWriteError: select.select([], [sock], [])
另請參見
asyncio
模組支援 非阻塞 SSL 套接字 並提供更高級別的 Streams API。 它使用 selectors
模組輪詢事件,並處理 SSLWantWriteError
、SSLWantReadError
和 BlockingIOError
異常。 它也非同步執行 SSL 握手。
記憶體 BIO 支援¶
在 3.5 版本中新增。
自從 Python 2.6 中引入 SSL 模組以來,SSLSocket
類提供了兩個相關但不同的功能領域
SSL 協議處理
網路 IO
網路 IO API 與 socket.socket
提供的 API 相同,SSLSocket
也從中繼承。 這允許將 SSL 套接字用作常規套接字的直接替換,從而使向現有應用程式新增 SSL 支援非常容易。
組合 SSL 協議處理和網路 IO 通常可以很好地工作,但在某些情況下卻不行。 一個示例是非同步 IO 框架,它們希望使用與 socket.socket
和內部 OpenSSL 套接字 IO 例程所假設的“基於檔案描述符的 select/poll” (基於就緒狀態)模型不同的 IO 多路複用模型。 這主要與 Windows 等平臺相關,在這種平臺上此模型效率不高。 為此,提供了一個縮小範圍的 SSLSocket
變體,稱為 SSLObject
。
- class ssl.SSLObject¶
SSLSocket
的縮小範圍變體,表示不包含任何網路 IO 方法的 SSL 協議例項。 此類通常由希望透過記憶體緩衝區為 SSL 實現非同步 IO 的框架作者使用。此類在 OpenSSL 實現的底層 SSL 物件之上實現了一個介面。 此物件捕獲 SSL 連線的狀態,但不提供任何網路 IO 本身。 IO 需要透過單獨的 “BIO” 物件執行,這些物件是 OpenSSL 的 IO 抽象層。
此類沒有公共建構函式。 必須使用
wrap_bio()
方法建立SSLObject
例項。 此方法將建立SSLObject
例項,並將其繫結到一對 BIO。 _傳入_ BIO 用於將資料從 Python 傳遞到 SSL 協議例項,而_傳出_ BIO 用於以相反的方式傳遞資料。以下方法可用
與
SSLSocket
相比,此物件缺少以下功能任何形式的網路 IO;
recv()
和send()
僅讀取和寫入到基礎MemoryBIO
緩衝區。沒有 _do_handshake_on_connect_ 機制。 您必須始終手動呼叫
do_handshake()
來啟動握手。沒有對 _suppress_ragged_eofs_ 的處理。 所有違反協議的檔案結尾條件都會透過
SSLEOFError
異常報告。與 SSL 套接字返回底層套接字不同,方法
unwrap()
呼叫不返回任何內容。傳遞給
SSLContext.set_servername_callback()
的 _server_name_callback_ 回撥將獲得一個SSLObject
例項,而不是SSLSocket
例項作為其第一個引數。
一些與使用
SSLObject
相關的重要說明對
SSLObject
的所有 IO 都是 非阻塞的。 這意味著例如,如果read()
需要比傳入 BIO 可用的更多資料,則會引發SSLWantReadError
。
在版本 3.7 中更改:
SSLObject
例項必須使用wrap_bio()
建立。 在早期版本中,可以直接建立例項。 這從未被記錄或正式支援過。
SSLObject 使用記憶體緩衝區與外部世界通訊。 類 MemoryBIO
提供了一個可用於此目的的記憶體緩衝區。 它包裝了一個 OpenSSL 記憶體 BIO(基本 IO)物件
SSL 會話¶
在版本 3.6 中新增。
安全注意事項¶
最佳預設值¶
對於客戶端使用,如果您的安全策略沒有任何特殊要求,強烈建議您使用 create_default_context()
函式來建立您的 SSL 上下文。它將載入系統受信任的 CA 證書,啟用證書驗證和主機名檢查,並嘗試選擇合理安全的協議和密碼設定。
例如,以下是如何使用 smtplib.SMTP
類來建立與 SMTP 伺服器的受信任的安全連線的示例
>>> 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()
新增。
相比之下,如果您透過自己呼叫 SSLContext
建構函式來建立 SSL 上下文,則預設情況下不會啟用證書驗證和主機名檢查。如果您這樣做,請閱讀以下段落以達到良好的安全級別。
手動設定¶
驗證證書¶
直接呼叫 SSLContext
建構函式時,預設值為 CERT_NONE
。由於它不驗證對方的身份,因此可能是不安全的,尤其是在客戶端模式下,您通常希望確保您正在與之通訊的伺服器的真實性。因此,在客戶端模式下,強烈建議使用 CERT_REQUIRED
。但是,它本身是不夠的;您還必須檢查透過呼叫 SSLSocket.getpeercert()
獲取的伺服器證書是否與所需的服務匹配。對於許多協議和應用程式,可以透過主機名識別服務。當啟用 SSLContext.check_hostname
時,會自動執行此常用檢查。
在 3.7 版本中更改: 主機名匹配現在由 OpenSSL 執行。Python 不再使用 match_hostname()
。
在伺服器模式下,如果您想使用 SSL 層對客戶端進行身份驗證(而不是使用更高級別的身份驗證機制),您還必須指定 CERT_REQUIRED
並類似地檢查客戶端證書。
協議版本¶
SSL 版本 2 和 3 被認為是不安全的,因此使用它們是危險的。如果想要客戶端和伺服器之間的最大相容性,建議使用 PROTOCOL_TLS_CLIENT
或 PROTOCOL_TLS_SERVER
作為協議版本。預設情況下停用 SSLv2 和 SSLv3。
>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.minimum_version = ssl.TLSVersion.TLSv1_3
>>> client_context.maximum_version = ssl.TLSVersion.TLSv1_3
上面建立的 SSL 上下文將僅允許 TLSv1.3 及更高版本(如果您的系統支援)連線到伺服器。PROTOCOL_TLS_CLIENT
預設情況下意味著證書驗證和主機名檢查。您必須將證書載入到上下文中。
密碼選擇¶
如果您有高階安全要求,可以透過 SSLContext.set_ciphers()
方法微調協商 SSL 會話時啟用的密碼。從 Python 3.2.3 開始,ssl 模組預設停用某些弱密碼,但您可能希望進一步限制密碼選擇。請務必閱讀 OpenSSL 關於 密碼列表格式 的文件。如果要檢查給定密碼列表啟用了哪些密碼,請使用 SSLContext.get_ciphers()
或系統上的 openssl ciphers
命令。
多程序¶
如果在多程序應用程式中使用此模組(例如,使用 multiprocessing
或 concurrent.futures
模組),請注意 OpenSSL 的內部隨機數生成器不能正確處理分叉的程序。如果應用程式使用任何帶有 os.fork()
的 SSL 功能,則必須更改父程序的 PRNG 狀態。任何成功呼叫 RAND_add()
或 RAND_bytes()
就足夠了。
TLS 1.3¶
3.7 版本新增。
TLS 1.3 協議的行為與以前版本的 TLS/SSL 略有不同。一些新的 TLS 1.3 功能尚未可用。
TLS 1.3 使用不相交的密碼套件集。預設情況下啟用所有 AES-GCM 和 ChaCha20 密碼套件。方法
SSLContext.set_ciphers()
尚不能啟用或停用任何 TLS 1.3 密碼,但SSLContext.get_ciphers()
會返回它們。會話票證不再作為初始握手的一部分發送,並且處理方式不同。
SSLSocket.session
和SSLSession
與 TLS 1.3 不相容。客戶端證書也不再在初始握手期間進行驗證。伺服器可以隨時請求證書。當客戶端從伺服器傳送或接收應用程式資料時,它們會處理證書請求。
尚不支援 TLS 1.3 功能,如早期資料、延遲 TLS 客戶端證書請求、簽名演算法配置和重新金鑰。
另請參見
- 類
socket.socket
底層
socket
類的文件- SSL/TLS 強加密:簡介
來自 Apache HTTP 伺服器文件的介紹
- RFC 1422: 網際網路電子郵件的隱私增強:第二部分:基於證書的金鑰管理
Steve Kent
- RFC 4086: 安全隨機性要求
Donald E., Jeffrey I. Schiller
- RFC 5280: 網際網路 X.509 公鑰基礎設施證書和證書吊銷列表 (CRL) 配置檔案
D. Cooper
- RFC 5246: 傳輸層安全 (TLS) 協議版本 1.2
T. Dierks 等人。
- RFC 6066:傳輸層安全(TLS)擴充套件
D. Eastlake
- IANA TLS:傳輸層安全(TLS)引數
IANA
- RFC 7525:關於安全使用傳輸層安全(TLS)和資料報傳輸層安全(DTLS)的建議
IETF
- Mozilla 的伺服器端 TLS 建議
Mozilla