python / 3.7.2rc1 / all / library-ssl.html

ssl —套接字对象的 TLS/SSL 包装器

源代码: Lib/ssl.py


此模块提供对 Client 端和服务器端网络套接字的传输层安全性(通常称为“安全套接字层”)加密和对等身份验证Function的访问。该模块使用 OpenSSL 库。只要在该平台上安装了 OpenSSL,它就可以在所有现代 Unix 系统,Windows,Mac OS X 以及可能的其他平台上使用。

Note

由于对 os 套接字 API 进行了调用,因此某些行为可能取决于平台。安装的 OpenSSL 版本也可能导致行为变化。例如,TLSv1.1 和 TLSv1.2 随附 openssl 版本 1.0.1.

Warning

请勿在未阅读Security considerations的情况下使用此模块。这样做可能会导致错误的安全感,因为 ssl 模块的默认设置不一定适合您的应用程序。

本节记录了ssl模块中的对象和Function;有关 TLS,SSL 和证书的更多常规信息,请参阅底部“另请参阅”部分中的文档。

此模块提供了一个类ssl.SSLSocket,该类派生自socket.socket类型,并提供类似于套接字的包装器,该包装器还使用 SSL 对pass套接字的数据进行加密和解密。它支持其他方法,例如getpeercert()(用于检索连接另一侧的证书)和cipher()(用于检索用于安全连接的密码)。

对于更复杂的应用程序,ssl.SSLContext类有助于 Management 设置和证书,然后可以passpassSSLContext.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.

函数,常量和异常

Socket creation

从 Python 3.2 和 2.7.9 开始,建议使用SSLContext实例的SSLContext.wrap_socket()将套接字包装为SSLSocket对象。辅助函数create_default_context()返回具有安全默认设置的新上下文。不推荐使用旧的wrap_socket()函数,因为它既效率低下,也不支持服务器名称指示(SNI)和主机名匹配。

具有默认上下文和 IPv4/IPv6 双栈的 Client 端套接字示例:

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 的 Client 端套接字示例:

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()
        ...

Context creation

便利Function可帮助创建SSLContext对象以用于常见目的。

  • ssl. create_default_context(* purpose = Purpose.SERVER_AUTH cafile = None capath = None cadata = None *)
    • 返回具有给定用途的默认设置的新SSLContext对象。这些设置由ssl模块选择,通常代表比直接调用SSLContext构造函数更高的安全级别。
  • cafile capath cadata *代表可选的 CA 证书,可信任该证书以进行证书验证,如SSLContext.load_verify_locations()。如果所有三个均为None,则此函数可以选择信任系统的默认 CA 证书。

设置为:具有高加密密码套件的PROTOCOL_TLSOP_NO_SSLv2OP_NO_SSLv3,而 RC4 和未经身份验证的密码套件。将SERVER_AUTH用作目的会将verify_mode设置为CERT_REQUIRED并加载 CA 证书(当至少给出* cafile capath cadata *之一时)或使用SSLContext.load_default_certs()加载默认的 CA 证书。

如果支持keylog_filename并且设置了环境变量 SSLKEYLOGFILE,则create_default_context()启用键记录。

Note

协议,选项,密码和其他设置可以随时更改为更具限制性的值,而无需事先弃用。这些值表示兼容性和安全性之间的合理平衡。

如果您的应用程序需要特定的设置,则应创建一个SSLContext并自己应用设置。

Note

如果您发现某些较旧的 Client 端或服务器try与此Function创建的SSLContext进行连接时收到错误消息,指出“协议或密码套件不匹配”,则可能是它们仅支持 SSL3.0,但此Function不使用OP_NO_SSLv3。 SSL3.0 被广泛认为是completely broken。如果您仍然希望 continue 使用此Function但仍允许 SSL 3.0 连接,则可以使用以下方法重新启用它们:

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

3.4 版的新Function。

在版本 3.4.4 中更改:从默认密码字符串中删除了 RC4.

在版本 3.6 中更改:ChaCha20/Poly1305 已添加到默认密码字符串。

从默认密码字符串中删除了 3 DES。

在 3.8 版中进行了更改:添加了对到 SSLKEYLOGFILE的密钥记录的支持。

Exceptions

  • exception ssl. SSLError
    • 引发 signal 以指示来自基础 SSL 实现的错误(当前由 OpenSSL 库提供)。这表示在底层网络连接上叠加的更高级别的加密和身份验证层中存在一些问题。此错误是OSError的子类型。 OpenSSL 库提供了SSLError个实例的错误代码和消息。

在版本 3.3 中更改:SSLError曾经是socket.error的子类型。

  • library
    • 一个字符串助记符,指定发生错误的 OpenSSL 子模块,例如SSLPEMX509。可能值的范围取决于 OpenSSL 版本。

版本 3.3 中的新Function。

  • reason
    • 一个字符串助记符,指示发生此错误的原因,例如CERTIFICATE_VERIFY_FAILED。可能值的范围取决于 OpenSSL 版本。

版本 3.3 中的新Function。

  • exception ssl. SSLZeroReturnError
    • try读取或写入时引发了SSLError的子类,并且 SSL 连接已完全关闭。请注意,这并不意味着基础传输(读取 TCP)已关闭。

版本 3.3 中的新Function。

  • exception ssl. SSLWantReadError
    • try读取或写入数据时,由非阻塞 SSL 套接字引发的SSLError子类,但是在满足请求之前,需要在基础 TCP 传输上接收更多数据。

版本 3.3 中的新Function。

  • exception ssl. SSLWantWriteError
    • try读取或写入数据时由非阻塞 SSL 套接字引发的SSLError子类,但是在满足请求之前,需要在基础 TCP 传输上发送更多数据。

版本 3.3 中的新Function。

  • exception ssl. SSLSyscallError
    • try在 SSL 套接字上执行操作时遇到系统错误时,将引发SSLError的子类。不幸的是,没有简单的方法来检查原始的 errno 号。

版本 3.3 中的新Function。

  • exception ssl. SSLEOFError
    • SSL 连接突然终止时引发的SSLError子类。通常,遇到此错误时,您不应try重用基础传输。

版本 3.3 中的新Function。

  • exception ssl. SSLCertVerificationError
    • 证书验证失败时引发的SSLError子类。

3.7 版中的新Function。

  • verify_code

    • 表示验证错误的数字错误编号。
  • verify_message

    • 可读的验证错误字符串。
  • exception ssl. CertificateError

在版本 3.7 中更改:现在,exception 是SSLCertVerificationError的别名。

Random generation

  • ssl. RAND_bytes(* num *)
    • 返回* num *个加密强度高的伪随机字节。如果 PRNG 尚未填充足够的数据或当前 RAND 方法不支持该操作,则引发SSLErrorRAND_status()可用于检查 PRNG 的状态,而RAND_add()可用于播种 PRNG。

对于几乎所有应用程序os.urandom()都是可取的。

阅读 Wikipedia 文章加密安全的伪随机数生成器(CSPRNG),以获取密码生成器的要求。

版本 3.3 中的新Function。

  • ssl. RAND_pseudo_bytes(* num *)
    • 返回值(字节,is_cryptographic):字节是* num *个伪随机字节,如果生成的字节在密码上很强,则 is_cryptographic 为True。如果当前 RAND 方法不支持该操作,则引发SSLError

如果生成的伪随机字节序列具有足够的长度,则它们将是唯一的,但不一定是不可预测的。它们可以用于非加密目的,也可以用于加密协议中的某些目的,但通常不用于密钥生成等。

对于几乎所有应用程序os.urandom()都是可取的。

版本 3.3 中的新Function。

从 3.6 版开始弃用:OpenSSL 已弃用ssl.RAND_pseudo_bytes(),而改用ssl.RAND_bytes()

  • ssl. RAND_status ( )

    • 如果已经为 SSL 伪随机数生成器提供了“足够”的随机性,则返回True,否则返回False。您可以使用ssl.RAND_egd()ssl.RAND_add()来增加伪随机数生成器的随机性。
  • ssl. RAND_egd(* path *)

    • 如果您在某个地方运行熵收集守护程序(EGD),并且* path *是向其打开的套接字连接的路径名,则它将从套接字读取 256 个字节的随机性,并将其添加到 SSL 伪随机数中生成器以增加生成的 Secret 密钥的安全性。通常只有在没有更好随机性的系统上才需要这样做。

有关熵收集守护程序的来源,请参见http://egd.sourceforge.net/http://prngd.sourceforge.net/

Availability:不适用于 LibreSSL 和 OpenSSL> 1.1.0.

  • ssl. RAND_add(* bytes entropy *)
    • 将给定的* bytes 混合到 SSL 伪随机数生成器中。参数 entropy *(浮点数)是字符串中包含的熵的下限(因此您可以始终使用0.0)。有关熵来源的更多信息,请参见 RFC 1750

在版本 3.5 中更改:现在接受可写bytes-like object

Certificate handling

  • ssl. match_hostname(* cert hostname *)
    • 验证* cert (以SSLSocket.getpeercert()返回的解码格式)匹配给定的 hostname *。所应用的规则是 RFC 2818 RFC 5280 RFC 6125中概述的用于检查 HTTPS 服务器身份的规则。除 HTTPS 之外,此Function还应适用于检查各种基于 SSL 的协议(例如 FTPS,IMAPS,POPS 等)中服务器的身份。

失败时引发CertificateError。成功时,该函数不返回任何内容:

>>> 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 版中的新Function。

在版本 3.3.3 中进行了更改:该函数现在遵循 RFC 6125(第 6.4.3 节),并且既不匹配多个通配符(例如*.*.com*a*.example.org),也不匹配国际化域名(IDN)片段内的通配符。仍支持 IDN A 标签,例如www*.xn--pthon-kva.org,但x*.python.org不再与xn--tda.python.org匹配。

在版本 3.5 中进行了更改:现在支持在证书的 subjectAltName 字段中存在 IP 地址的匹配。

在版本 3.7 中更改:该Function不再用于 TLS 连接。主机名匹配现在由 OpenSSL 执行。

当它是该段中最左边和唯一的字符时,允许使用通配符。不再支持部分通配符(例如www*.example.com)。

从 3.7 版开始不推荐使用。

  • ssl. cert_time_to_seconds(* cert_time *)
    • "%b %d %H:%M:%S %Y %Z" strptime 格式(C 语言环境)给定的cert_time字符串表示来自证书的“ 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”日期必须使用格林尼治标准时间( RFC 5280)。

在版本 3.5 中更改:将 Importing 时间解释为 UTC 中 Importing 字符串中“ GMT”时区指定的时间。以前使用本地时区。返回一个整数(Importing 格式中不包括秒)

  • ssl. get_server_certificate(* addr ssl_version = PROTOCOL_TLS ca_certs = None *)
    • 给定受 SSL 保护的服务器的地址addr,作为(* hostname port-number *)对,获取服务器的证书,并将其作为 PEM 编码的字符串返回。如果指定ssl_version,则使用该版本的 SSL 协议try连接到服务器。如果指定了ca_certs,则它应该是包含根证书列表的文件,该格式与SSLContext.wrap_socket()中的相同参数所使用的格式相同。该调用将try根据该组根证书来验证服务器证书,并且如果验证try失败将失败。

在版本 3.3 中更改:此Function现在与 IPv6 兼容。

在版本 3.5 中进行了更改:默认* ssl_version *从PROTOCOL_SSLv3更改为PROTOCOL_TLS,以最大程度地与现代服务器兼容。

  • ssl. DER_cert_to_PEM_cert(* DER_cert_bytes *)

    • 给定证书作为 DER 编码的字节块,则返回同一证书的 PEM 编码的字符串版本。
  • ssl. PEM_cert_to_DER_cert(* PEM_cert_string *)

    • 给定证书为 ASCII PEM 字符串,则返回该证书的 DER 编码字节序列。
  • ssl. get_default_verify_paths ( )

  • cafile-解析到 cafile 的路径,或者None(如果文件不存在),

  • capath-已解析为 capath 的路径;如果目录不存在,则为None

  • openssl_cafile_env-指向 cafile 的 OpenSSL 环境密钥,

  • openssl_cafile-cafile 的硬编码路径,

  • openssl_capath_env-OpenSSL 的环境密钥,它指向一个安全范围,

  • openssl_capath-Capath 目录的硬编码路径

Availability:LibreSSL 忽略环境变量openssl_cafile_envopenssl_capath_env

3.4 版的新Function。

  • ssl. enum_certificates(* store_name *)
    • 从 Windows 的系统证书库中检索证书。 * store_name *可以是CAROOTMY之一。 Windows 也可能提供其他证书存储。

该函数返回(cert_bytes,encoding_type,trust)Tuples 的列表。 encoding_type 指定 cert_bytes 的编码。对于 X.509 ASN.1 数据,它是x509_asn;对于 PKCS#7 ASN.1 数据,它是pkcs_7_asn。信任将证书的目的指定为一组 OIDS,或者如果证书对所有目的都是可信任的,则将其确切指定为True

Example:

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

Availability: Windows.

3.4 版的新Function。

  • ssl. enum_crls(* store_name *)
    • 从 Windows 的系统证书库中检索 CRL。 * store_name *可以是CAROOTMY之一。 Windows 也可能提供其他证书存储。

该函数返回(cert_bytes,encoding_type,trust)Tuples 的列表。 encoding_type 指定 cert_bytes 的编码。对于 X.509 ASN.1 数据,它是x509_asn;对于 PKCS#7 ASN.1 数据,它是pkcs_7_asn

Availability: Windows.

3.4 版的新Function。

  • 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 prevent_ragged_eofs = True ciphers = None *)

在内部,函数创建一个SSLContext,协议为* ssl_version ,而SSLContext.options设置为 cert_reqs 。如果设置了参数 keyfile certfile ca_certs ciphers *,则将这些值传递给SSLContext.load_cert_chain()SSLContext.load_verify_locations()SSLContext.set_ciphers()

参数* server_side do_handshake_on_connect suppress_ragged_eofs *具有与SSLContext.wrap_socket()相同的含义。

从 3.7 版开始不推荐使用:从 Python 3.2 和 2.7.9 开始,建议使用SSLContext.wrap_socket()而不是wrap_socket()。顶级Function受到限制,并会创建不安全的 Client 端套接字,而不会显示服务器名称或主机名。

Constants

Note

现在,所有常量都是enum.IntEnumenum.IntFlag集合。

3.6 版的新Function。

  • ssl. CERT_NONE
    • SSLContext.verify_mode的可能值,或wrap_socket()cert_reqs参数。除PROTOCOL_TLS_CLIENT外,它是默认模式。使用 Client 端套接字,几乎可以接受任何证书。验证错误(例如不受信任或过期的证书)将被忽略,并且不会中止 TLS/SSL 握手。

在服务器模式下,不从 Client 端请求任何证书,因此 Client 端不发送任何用于 Client 端证书身份验证的证书。

请参阅下面对Security considerations的讨论。

在服务器模式下,Client 端证书请求将发送到 Client 端。Client 端可以忽略请求或发送证书以执行 TLSClient 端证书身份验证。如果 Client 端选择发送证书,则将对其进行验证。任何验证错误都会立即中止 TLS 握手。

使用此设置要求将一组有效的 CA 证书传递给SSLContext.load_verify_locations()或作为ca_certs参数的值传递给wrap_socket()

使用服务器套接字,此模式提供强制的 TLSClient 端证书认证。Client 端证书请求将发送到 Client 端,并且 Client 端必须提供有效且受信任的证书。

使用此设置要求将一组有效的 CA 证书传递给SSLContext.load_verify_locations()或作为ca_certs参数的值传递给wrap_socket()

  • 类别 ssl. VerifyMode

3.6 版的新Function。

  • ssl. VERIFY_DEFAULT
    • SSLContext.verify_flags的可能值。在这种模式下,不检查证书吊销列表(CRL)。默认情况下,OpenSSL 既不需要也不验证 CRL。

3.4 版的新Function。

  • ssl. VERIFY_CRL_CHECK_LEAF
    • SSLContext.verify_flags的可能值。在此模式下,仅检查对等证书,而不检查中间 CA 证书。该模式需要由对等证书的颁发者(其直接祖先 CA)签名的有效 CRL。如果尚未使用SSLContext.load_verify_locations加载适当的 CRL,则验证将失败。

3.4 版的新Function。

  • ssl. VERIFY_CRL_CHECK_CHAIN

3.4 版的新Function。

3.4 版的新Function。

  • ssl. VERIFY_X509_TRUSTED_FIRST
    • SSLContext.verify_flags的可能值。它指示 OpenSSL 在构建用于验证证书的信任链时首选可信任证书。默认情况下启用此标志。

3.4.4 版的新Function。

  • 类别 ssl. VerifyFlags

3.6 版的新Function。

  • ssl. PROTOCOL_TLS
    • 选择 Client 端和服务器都支持的最高协议版本。尽管名称,此选项可以选择“ SSL”和“ TLS”协议。

3.6 版的新Function。

3.6 版的新Function。

  • ssl. PROTOCOL_TLS_SERVER

3.6 版的新Function。

自版本 3.6 起不推荐使用:改为使用PROTOCOL_TLS

  • ssl. PROTOCOL_SSLv2
    • 选择 SSL 版本 2 作为通道加密协议。

如果 OpenSSL 是使用OPENSSL_NO_SSL2标志编译的,则此协议不可用。

Warning

SSL 版本 2 不安全。不鼓励使用它。

自版本 3.6 起不推荐使用:OpenSSL 删除了对 SSLv2 的支持。

  • ssl. PROTOCOL_SSLv3
    • 选择 SSL 版本 3 作为通道加密协议。

如果 OpenSSL 是使用OPENSSL_NO_SSLv3标志编译的,则此协议不可用。

Warning

SSL 版本 3 不安全。不鼓励使用它。

自版本 3.6 起不推荐使用:OpenSSL 不推荐所有特定于版本的协议。请使用默认协议PROTOCOL_TLSOP_NO_SSLv3等标志。

  • ssl. PROTOCOL_TLSv1
    • 选择 TLS 版本 1.0 作为通道加密协议。

自版本 3.6 起不推荐使用:OpenSSL 不推荐所有特定于版本的协议。请使用默认协议PROTOCOL_TLSOP_NO_SSLv3等标志。

  • ssl. PROTOCOL_TLSv1_1
    • 选择 TLS 版本 1.1 作为通道加密协议。仅适用于 openssl 版本 1.0.1.

3.4 版的新Function。

自版本 3.6 起不推荐使用:OpenSSL 不推荐所有特定于版本的协议。请使用默认协议PROTOCOL_TLSOP_NO_SSLv3等标志。

  • ssl. PROTOCOL_TLSv1_2
    • 选择 TLS 版本 1.2 作为通道加密协议。这是最现代的版本,而且如果双方都能说的话,可能是获得最大保护的最佳选择。仅适用于 openssl 版本 1.0.1.

3.4 版的新Function。

自版本 3.6 起不推荐使用:OpenSSL 不推荐所有特定于版本的协议。请使用默认协议PROTOCOL_TLSOP_NO_SSLv3等标志。

  • ssl. OP_ALL
    • 为其他 SSL 实现中存在的各种错误启用解决方法。默认情况下设置此选项。它不必设置与 OpenSSL 的SSL_OP_ALL常量相同的标志。

3.2 版中的新Function。

  • ssl. OP_NO_SSLv2
    • 阻止 SSLv2 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 SSLv2 作为协议版本。

3.2 版中的新Function。

自版本 3.6 起不推荐使用:不推荐使用 SSLv2

  • ssl. OP_NO_SSLv3
    • 阻止 SSLv3 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 SSLv3 作为协议版本。

3.2 版中的新Function。

自版本 3.6 起不推荐使用:不推荐使用 SSLv3

  • ssl. OP_NO_TLSv1
    • 阻止 TLSv1 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 TLSv1 作为协议版本。

3.2 版中的新Function。

从 3.7 版开始不推荐使用:从 OpenSSL 1.1.0 开始不推荐使用该选项,请改用新的SSLContext.minimum_versionSSLContext.maximum_version

  • ssl. OP_NO_TLSv1_1
    • 阻止 TLSv1.1 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 TLSv1.1 作为协议版本。仅适用于 openssl 版本 1.0.1.

3.4 版的新Function。

从 3.7 版开始不推荐使用:从 OpenSSL 1.1.0 开始不推荐使用该选项。

  • ssl. OP_NO_TLSv1_2
    • 阻止 TLSv1.2 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 TLSv1.2 作为协议版本。仅适用于 openssl 版本 1.0.1.

3.4 版的新Function。

从 3.7 版开始不推荐使用:从 OpenSSL 1.1.0 开始不推荐使用该选项。

  • ssl. OP_NO_TLSv1_3
    • 阻止 TLSv1.3 连接。此选项仅与PROTOCOL_TLS结合使用。这样可以防止对等方选择 TLSv1.3 作为协议版本。 TLS 1.3 可用于 OpenSSL 1.1.1 或更高版本。针对旧版本的 OpenSSL 编译 Python 后,该标志默认为* 0 *。

3.7 版中的新Function。

从 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 和更早版本中的所有重新协商。不要发送 HelloRequest 消息,而忽略pass ClientHello 进行的重新协商请求。

此选项仅在 OpenSSL 1.1.0h 及更高版本中可用。

3.7 版中的新Function。

  • ssl. OP_CIPHER_SERVER_PREFERENCE
    • 使用服务器的密码排序首选项,而不是 Client 端的密码。此选项对 Client 端套接字和 SSLv2 服务器套接字无效。

版本 3.3 中的新Function。

  • ssl. OP_SINGLE_DH_USE
    • 防止针对不同的 SSL 会话重复使用相同的 DH 密钥。这提高了前向保密性,但是需要更多的计算资源。此选项仅适用于服务器套接字。

版本 3.3 中的新Function。

  • ssl. OP_SINGLE_ECDH_USE
    • 防止针对不同的 SSL 会话重复使用相同的 ECDH 密钥。这提高了前向保密性,但是需要更多的计算资源。此选项仅适用于服务器套接字。

版本 3.3 中的新Function。

  • ssl. OP_ENABLE_MIDDLEBOX_COMPAT
    • 在 TLS 1.3 握手中发送虚拟的更改密码规范(CCS)消息,以使 TLS 1.3 连接看起来更像是 TLS 1.2 连接。

此选项仅在 OpenSSL 1.1.1 和更高版本中可用。

3.8 版的新Function。

  • ssl. OP_NO_COMPRESSION
    • 禁用 SSL 通道上的压缩。如果应用程序协议支持其自己的压缩方案,这将很有用。

此选项仅在 OpenSSL 1.0.0 和更高版本中可用。

版本 3.3 中的新Function。

  • 类别 ssl. Options

  • ssl. OP_NO_TICKET

    • 阻止 Client 端请求会话票证。

3.6 版的新Function。

  • ssl. HAS_ALPN
    • RFC 7301中所述,OpenSSL 库是否具有对* Application-Layer Protocol Negotiation * TLS 扩展的内置支持。

3.5 版中的新Function。

3.7 版中的新Function。

  • ssl. HAS_ECDH
    • OpenSSL 库是否内置支持基于椭圆曲线的 Diffie-Hellman 密钥交换。除非发布者明确禁用了此Function,否则应该为 true。

版本 3.3 中的新Function。

  • ssl. HAS_SNI
    • OpenSSL 库是否对* Server Name Indication *扩展(在 RFC 6066中定义)具有内置支持。

3.2 版中的新Function。

版本 3.3 中的新Function。

  • ssl. HAS_SSLv2
    • OpenSSL 库是否具有对 SSL 2.0 协议的内置支持。

3.7 版中的新Function。

  • ssl. HAS_SSLv3
    • OpenSSL 库是否具有对 SSL 3.0 协议的内置支持。

3.7 版中的新Function。

  • ssl. HAS_TLSv1
    • OpenSSL 库是否具有对 TLS 1.0 协议的内置支持。

3.7 版中的新Function。

  • ssl. HAS_TLSv1_1
    • OpenSSL 库是否具有对 TLS 1.1 协议的内置支持。

3.7 版中的新Function。

  • ssl. HAS_TLSv1_2
    • OpenSSL 库是否具有对 TLS 1.2 协议的内置支持。

3.7 版中的新Function。

  • ssl. HAS_TLSv1_3
    • OpenSSL 库是否具有对 TLS 1.3 协议的内置支持。

3.7 版中的新Function。

版本 3.3 中的新Function。

  • ssl. OPENSSL_VERSION
    • 解释器加载的 OpenSSL 库的版本字符串:
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.0.2k  26 Jan 2017'

3.2 版中的新Function。

  • ssl. OPENSSL_VERSION_INFO
    • 五个整数的 Tuples,表示有关 OpenSSL 库的版本信息:
>>> ssl.OPENSSL_VERSION_INFO
(1, 0, 2, 11, 15)

3.2 版中的新Function。

  • ssl. OPENSSL_VERSION_NUMBER
    • OpenSSL 库的原始版本号,以单个整数表示:
>>> ssl.OPENSSL_VERSION_NUMBER
268443839
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
'0x100020bf'

3.2 版中的新Function。

  • ssl. ALERT_DESCRIPTION_HANDSHAKE_FAILURE

  • ssl. ALERT_DESCRIPTION_INTERNAL_ERROR

  • ALERT_DESCRIPTION_*

用作SSLContext.set_servername_callback()中的回调函数的返回值。

3.4 版的新Function。

  • 类别 ssl. AlertDescription

3.6 版的新Function。

3.4 版的新Function。

3.4 版的新Function。

  • 类别 ssl. SSLErrorNumber

3.6 版的新Function。

3.7 版中的新Function。

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

SSL Sockets

但是,由于 SSL(和 TLS)协议在 TCP 之上有其自己的框架,因此 SSL 套接字抽象在某些方面可能会偏离正常的 OS 级别套接字的规范。尤其参见非阻塞 socket 的注意事项

必须使用SSLContext.wrap_socket()方法创建SSLSocket的实例。

在版本 3.5 中进行了更改:添加了sendfile()方法。

在版本 3.5 中更改:每次接收或发送字节时,shutdown()不会重置套接字超时。现在,套接字超时已达到关闭的最大总持续时间。

从 3.6 版开始不推荐使用:不推荐直接创建SSLSocket实例,使用SSLContext.wrap_socket()封装套接字。

在 3.7 版中进行了更改:SSLSocket实例必须使用wrap_socket()创建。在早期版本中,可以直接创建实例。从未记录或得到官方支持。

SSL 套接字还具有以下其他方法和属性:

  • SSLSocket. read(* len = 1024 buffer = None *)
    • 从 SSL 套接字读取最多* len 个字节的数据,并将结果作为bytes实例返回。如果指定了 buffer *,则改为读入缓冲区,并返回读取的字节数。

如果套接字为non-blocking并且读会阻塞,则提高SSLWantReadErrorSSLWantWriteError

由于在任何时候都可以进行重新协商,因此对read()的调用也会引起写操作。

在版本 3.5 中更改:每次接收或发送字节时,套接字超时都不再重置。现在,套接字超时已达到最大总持续时间,最多可以读取* len *个字节。

从 3.6 版开始不推荐使用:使用recv()而不是read()

  • SSLSocket. write(* buf *)
    • 将* buf *写入 SSL 套接字,并返回写入的字节数。 * buf *参数必须是支持缓冲区接口的对象。

如果套接字为non-blocking,则写SSLWantReadErrorSSLWantWriteError,并且写操作会阻塞。

由于在任何时候都可以进行重新协商,因此对write()的调用也会引起读取操作。

在版本 3.5 中更改:每次接收或发送字节时,套接字超时都不再重置。现在,套接字超时已达到写入* buf *的最大总持续时间。

从 3.6 版开始不推荐使用:使用send()而不是write()

Note

read()write()方法是低级方法,用于读取和写入未加密的应用程序级数据,并将其解密/加密为加密的有线级数据。这些方法需要有效的 SSL 连接,即握手已完成且未调用SSLSocket.unwrap()

通常,您应该使用诸如recv()send()之类的套接字 API 方法来代替这些方法。

  • SSLSocket. do_handshake ( )
    • 执行 SSL 设置握手。

在版本 3.4 中进行了更改:当套接字的contextcheck_hostname属性为 true 时,握手方法还将执行match_hostname()

在版本 3.5 中更改:每次接收或发送字节时,套接字超时都不再重置。现在,套接字超时已达到最大握手总持续时间。

在版本 3.7 中更改:握手期间,OpenSSL 匹配了主机名或 IP 地址。不再使用Functionmatch_hostname()。如果 OpenSSL 拒绝主机名或 IP 地址,则握手会提前中止,并且 TLS 警报消息会发送到对等方。

  • SSLSocket. getpeercert(* binary_form = False *)
    • 如果连接另一端没有对等方的证书,则返回None。如果尚未完成 SSL 握手,请引发ValueError

如果binary_form参数是False,并且从对等方接收到证书,则此方法返回dict实例。如果证书未pass验证,则字典为空。如果证书已pass验证,它将返回包含几个密钥的字典,其中包括subject(颁发证书的主体)和issuer(颁发证书的主体)。如果证书包含* Subject Alternative Name *extensions 的实例(请参见 RFC 3280),则词典中还将有一个subjectAltName密钥。

subjectissuer字段是 Tuples,包含在证书的数据结构中为各个字段提供的相对专有名称(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}

Note

要验证特定服务的证书,可以使用match_hostname()Function。

如果binary_form参数是True,并且提供了证书,则此方法以字节序列的形式返回整个证书的 DER 编码形式,如果对等方未提供证书,则返回None。对等方是否提供证书取决于 SSL 套接字的角色:

  • 对于 Client 端 SSL 套接字,无论是否需要验证,服务器将始终提供证书;

  • 对于服务器 SSL 套接字,Client 端仅在服务器请求时才提供证书;因此,如果您使用CERT_NONE(而不是CERT_OPTIONALCERT_REQUIRED),则getpeercert()将返回None

在版本 3.2 中进行了更改:返回的字典包含其他项,例如issuernotBefore

在版本 3.4 中更改:未完成握手时引发ValueError。返回的字典包含其他 X509v3 扩展项,例如crlDistributionPointscaIssuersOCSP URI。

在版本 3.8.1 中更改:IPv6 地址字符串不再包含尾随新行。

  • SSLSocket. cipher ( )

    • 返回一个三值 Tuples,其中包含正在使用的密码的名称,定义其使用的 SSL 协议的版本以及正在使用的 Secret 位数。如果未构建连接,则返回None
  • SSLSocket. shared_ciphers ( )

    • 返回握手期间 Client 端共享的密码列表。返回列表的每个条目都是一个三值 Tuples,其中包含密码的名称,定义其使用方式的 SSL 协议的版本以及密码使用的 Secret 位数。如果未构建连接或套接字是 Client 端套接字,则shared_ciphers()返回None

3.5 版中的新Function。

  • SSLSocket. compression ( )
    • 返回用作字符串的压缩算法,如果未压缩连接,则返回None

如果更高级别的协议支持其自己的压缩机制,则可以使用OP_NO_COMPRESSION禁用 SSL 级别的压缩。

版本 3.3 中的新Function。

  • SSLSocket. get_channel_binding(* cb_type =“ tls-unique” *)
    • 获取当前连接的通道绑定数据(作为字节对象)。如果未连接或握手尚未完成,则返回None
  • cb_type *参数允许选择所需的通道绑定类型。有效的 Channels 绑定类型在CHANNEL_BINDING_TYPES列表中列出。当前仅支持由 RFC 5929定义的“ tls-unique”通道绑定。如果请求的通道绑定类型不受支持,则会引发ValueError

版本 3.3 中的新Function。

  • SSLSocket. selected_alpn_protocol ( )
    • 返回在 TLS 握手期间选择的协议。如果未调用SSLContext.set_alpn_protocols(),则另一方不支持 ALPN,如果此套接字不支持 Client 端提出的任何协议,或者尚未进行握手,则返回None

3.5 版中的新Function。

  • SSLSocket. selected_npn_protocol ( )
    • 返回在 TLS/SSL 握手期间选择的高级协议。如果未调用SSLContext.set_npn_protocols(),或者另一方不支持 NPN,或者握手尚未发生,则将返回None

版本 3.3 中的新Function。

  • SSLSocket. unwrap ( )

    • 执行 SSL 关闭握手,这将从基础套接字中删除 TLS 层,并返回基础套接字对象。这可用于从pass连接的加密操作到未加密。返回的套接字应始终用于与连接的另一端进行进一步的通信,而不是原始套接字。
  • SSLSocket. verify_client_post_handshake ( )

    • 从 TLS 1.3Client 端请求握手后身份验证(PHA)。在初始 TLS 握手之后且双方均启用了 PHA 之后,只能从服务器端套接字为 TLS 1.3 连接启动 PHA,请参见SSLContext.post_handshake_auth

该方法不会立即执行证书交换。服务器端在下一个写事件期间发送一个 CertificateRequest,并期望 Client 端在下一个读事件中以证书作为响应。

如果不满足任何前提条件(例如,不支持 TLS 1.3,未启用 PHA),则会引发SSLError

Note

仅在启用 OpenSSL 1.1.1 和 TLS 1.3 的情况下可用。没有 TLS 1.3 支持,该方法将引发NotImplementedError

3.8 版的新Function。

  • SSLSocket. version ( )
    • 以字符串形式返回由连接协商的实际 SSL 协议版本,或者None未构建安全连接。在撰写本文时,可能的返回值包括"SSLv2""SSLv3""TLSv1""TLSv1.1""TLSv1.2"。最新的 OpenSSL 版本可能会定义更多的返回值。

3.5 版中的新Function。

  • SSLSocket. pending ( )

    • 返回可读取的已解密字节数,该字节待连接。
  • SSLSocket. context

3.2 版中的新Function。

  • SSLSocket. server_side
    • 一个布尔值,对于服务器端套接字是True,对于 Client 端套接字是False

3.2 版中的新Function。

  • SSLSocket. server_hostname
    • 服务器的主机名:str类型,如果是服务器端套接字,则为None,或者在构造函数中未指定主机名。

3.2 版中的新Function。

在版本 3.7 中更改:该属性现在始终是 ASCII 文本。当server_hostname是国际化域名(IDN)时,此属性现在存储 A 标签形式("xn--pythn-mua.org"),而不是 U 标签形式("pythön.org")。

  • SSLSocket. session
    • 此 SSL 连接的SSLSession。执行 TLS 握手后,该会话可用于 Client 端和服务器端套接字。对于 Client 端套接字,可以在调用do_handshake()重用会话之前设置会话。

3.6 版的新Function。

  • SSLSocket. session_reused
    • 3.6 版的新Function。

SSL Contexts

3.2 版中的新Function。

SSL 上下文包含比单个 SSL 连接更长寿的各种数据,例如 SSL 配置选项,证书和私钥。它还可以为服务器端套接字 ManagementSSL 会话的缓存,以加快来自同一 Client 端的重复连接。

  • 类别 ssl. SSLContext(*协议= PROTOCOL_TLS *)
    • 创建一个新的 SSL 上下文。您可以传递* protocol *,该协议必须是此模块中定义的PROTOCOL_*常量之一。该参数指定要使用的 SSL 协议版本。通常,服务器选择特定的协议版本,并且 Client 端必须适应服务器的选择。大多数版本不能与其他版本互操作。如果未指定,则默认为PROTOCOL_TLS;它提供与其他版本的最大兼容性。

下表显示了 Client 端(侧面)中的哪些版本可以连接到服务器(顶部)中的哪些版本:

Note

Client 端服务器* SSLv2 SSLv3 TLS [3] TLSv1 TLSv1.1 TLSv1.2
SSLv2 yes no no [1] no no no
SSLv3 no yes no [2] no no no
* TLS ( SSLv23 *)[3] no [1] no [2] yes yes yes yes
TLSv1 no no yes yes no no
TLSv1.1 no no yes no yes no
TLSv1.2 no no yes no no yes

Footnotes

See also

create_default_context()使ssl模块为给定目的选择安全设置。

在版本 3.6 中更改:使用安全的默认值创建上下文。默认设置选项OP_NO_COMPRESSIONOP_CIPHER_SERVER_PREFERENCEOP_SINGLE_DH_USEOP_SINGLE_ECDH_USEOP_NO_SSLv2(PROTOCOL_SSLv2除外)和OP_NO_SSLv3(PROTOCOL_SSLv3除外)。初始密码套件列表仅包含HIGH个密码,没有NULL个密码,也没有MD5个密码(PROTOCOL_SSLv2除外)。

SSLContext对象具有以下方法和属性:

  • SSLContext. cert_store_stats ( )
    • 获取有关已加载的 X.509 证书的数量,标记为 CA 证书的 X.509 证书的数量以及字典的证书吊销列表的统计信息。

具有一个 CA 证书和另一个证书的上下文示例:

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

3.4 版的新Function。

  • SSLContext. load_cert_chain(* certfile keyfile = None password = None *)
    • 加载私钥和相应的证书。 * certfile *字符串必须是包含证书以及构建证书真实性所需的任意数量的 CA 证书的 PEM 格式的单个文件的路径。 * keyfile 字符串(如果存在)必须指向包含私钥的文件。否则,私钥也将从 certfile 获取。有关如何将证书存储在 certfile *中的更多信息,请参见Certificates的讨论。
  • password 参数可以是一个函数,用于获取用于解密私钥的密码。仅当私钥已加密并且需要密码时,才会调用该函数。它将不带任何参数地被调用,并且它应该返回一个字符串,字节或字节数组。如果返回值为字符串,则在使用它解密密钥之前,它将被编码为 UTF-8.另外,字符串,字节或字节数组值可以直接作为 password *参数提供。如果私钥未加密并且不需要密码,它将被忽略。

如果未指定* password *参数并且需要密码,则将使用 OpenSSL 的内置密码提示机制以交互方式提示用户 Importing 密码。

如果私钥与证书不匹配,则会引发SSLError

在版本 3.3 中更改:新的可选参数* password *。

  • SSLContext. load_default_certs(* purpose = Purpose.SERVER_AUTH *)
    • 从默认位置加载一组默认的“证书颁发机构”(CA)证书。在 Windows 上,它将从CAROOT系统存储中加载 CA 证书。在其他系统上,它称为SSLContext.set_default_verify_paths()。将来,该方法也可能会从其他位置加载 CA 证书。
  • purpose *标志指定加载哪种 CA 证书。默认设置Purpose.SERVER_AUTH加载为 TLS Web 服务器身份验证(Client 端套接字)标记并受信任的证书。 Purpose.CLIENT_AUTH在服务器端加载 CA 证书以进行 Client 端证书验证。

3.4 版的新Function。

  • SSLContext. load_verify_locations(* cafile = None capath = None cadata = None *)
    • verify_mode不是CERT_NONE时,加载一组用于验证其他对等方证书的“证书颁发机构”(CA)证书。必须指定* cafile capath *至少之一。

此方法还可以加载 PEM 或 DER 格式的证书吊销列表(CRL)。为了使用 CRL,必须正确配置SSLContext.verify_flags

  • cafile *字符串(如果存在)是 PEM 格式的级联 CA 证书文件的路径。有关如何在此文件中排列证书的更多信息,请参见Certificates的讨论。

  • capath *字符串(如果存在)是指向目录的路径,该目录包含多个OpenSSL 特定的布局之后的 PEM 格式的 CA 证书。

  • cadata 对象(如果存在)是一个或多个 PEM 编码证书的 ASCII 字符串或 DER 编码证书的bytes-like object。与 capath *一样,PEM 编码证书周围的多余行将被忽略,但至少必须存在一个证书。

在版本 3.4 中更改:新的可选参数* cadata *

  • SSLContext. get_ca_certs(* binary_form = False *)
    • 获取已加载的“证书颁发机构”(CA)证书的列表。如果binary_form参数是False,则每个列表条目都是 dict,就像SSLSocket.getpeercert()的输出一样。否则,该方法将返回 DER 编码证书的列表。除非 SSL 连接请求并加载了证书,否则返回的列表不包含来自* capath *的证书。

Note

除非至少使用过一次,否则不会加载 capath 目录中的证书。

3.4 版的新Function。

  • SSLContext. get_ciphers ( )

Example:

>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
>>> ctx.get_ciphers()  # OpenSSL 1.0.x
[{'alg_bits': 256,
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'id': 50380848,
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 256},
 {'alg_bits': 128,
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'id': 50380847,
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 128}]

在 OpenSSL 1.1 和更高版本上,密码 dict 包含其他字段:

>>> ctx.get_ciphers()  # OpenSSL 1.1+
[{'aead': True,
  'alg_bits': 256,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'digest': None,
  'id': 50380848,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1.2',
  'strength_bits': 256,
  'symmetric': 'aes-256-gcm'},
 {'aead': True,
  'alg_bits': 128,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'digest': None,
  'id': 50380847,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1.2',
  'strength_bits': 128,
  'symmetric': 'aes-128-gcm'}]

Availability:OpenSSL 1.0.2.

3.6 版的新Function。

  • SSLContext. set_default_verify_paths ( )

    • 从构建 OpenSSL 库时定义的文件系统路径中加载一组默认的“证书颁发机构”(CA)证书。不幸的是,没有简单的方法可以知道该方法是否成功:如果找不到证书,则不会返回错误。但是,当 OpenSSL 库作为 os 的一部分提供时,它可能已正确配置。
  • SSLContext. set_ciphers(密码)

    • 设置使用此上下文创建的套接字的可用密码。它应该是OpenSSL 密码列表格式中的字符串。如果无法选择密码(因为编译时选项或其他配置禁止使用所有指定的密码),则将引发SSLError

Note

连接后,SSL 套接字的SSLSocket.cipher()方法将提供当前选择的密码。

默认情况下,OpenSSL 1.1.1 启用了 TLS 1.3 密码套件。无法使用set_ciphers()禁用套件。

  • SSLContext. set_alpn_protocols(协议)
    • 指定套接字在 SSL/TLS 握手期间应通告的协议。它应该是按喜好排序的 ASCII 字符串列表,例如['http/1.1', 'spdy/2']。协议的选择将在握手期间进行,并根据 RFC 7301进行播放。握手成功后,SSLSocket.selected_alpn_protocol()方法将返回约定的协议。

如果HAS_ALPNFalse,则此方法将引发NotImplementedError

当双方都支持 ALPN 但无法在协议上达成共识时,OpenSSL 1.1.0 到 1.1.0e 将中止握手并引发SSLError。 1.1.0f 的行为类似于 1.0.2,SSLSocket.selected_alpn_protocol()返回 None。

3.5 版中的新Function。

  • SSLContext. set_npn_protocols(协议)
    • 指定套接字在 SSL/TLS 握手期间应通告的协议。它应该是按喜好排序的字符串列表,例如['http/1.1', 'spdy/2']。协议的选择将在握手期间进行,并根据应用层协议协商进行播放。握手成功后,SSLSocket.selected_npn_protocol()方法将返回约定的协议。

如果HAS_NPNFalse,则此方法将引发NotImplementedError

版本 3.3 中的新Function。

  • SSLContext. sni_callback
    • 注册一个回调函数,当 TLSClient 端指定服务器名称指示时,SSL/TLS 服务器接收到 TLSClient 端 Hello 握手消息后将调用该回调函数。服务器名称指示机制在 RFC 6066第 3 部分-服务器名称指示中指定。

每个SSLContext只能设置一个回调。如果* sni_callback *设置为None,则禁用回调。随后调用此函数将禁用以前注册的回调。

回调函数将使用三个参数来调用。第一个是ssl.SSLSocket,第二个是代表 Client 端打算通信的服务器名称的字符串(如果 TLSClient 端 Hello 不包含服务器名称,则为None),第三个参数是原始SSLContext。服务器名称参数是文本。对于国际化域名,服务器名称是 IDN A 标签("xn--pythn-mua.org")。

此回调的典型用法是将ssl.SSLSocketSSLSocket.context属性更改为SSLContext类型的新对象,该对象表示与服务器名称匹配的证书链。

由于 TLS 连接处于早期协商阶段,因此只能使用有限的方法和属性,例如SSLSocket.selected_alpn_protocol()SSLSocket.contextSSLSocket.getpeercert()SSLSocket.getpeercert()SSLSocket.cipher()SSLSocket.compress()方法要求 TLS 连接已超出 TLSClient 端 Hello 的范围,因此将不包含返回有意义的值,也无法对其进行安全调用。

如果* sni_callback *函数引发异常,则 TLS 连接将以致命的 TLS 警报消息ALERT_DESCRIPTION_HANDSHAKE_FAILURE终止。

如果 OpenSSL 库在构建时定义了 OPENSSL_NO_TLSEXT,则此方法将引发NotImplementedError

3.7 版中的新Function。

  • SSLContext. set_servername_callback(* server_name_callback *)
    • 这是为向后兼容保留的旧版 API。如果可能,应改为使用sni_callback。给定的* server_name_callback sni_callback 相似,不同之处在于,当服务器主机名是 IDN 编码的国际化域名时, server_name_callback *会收到一个已解码的 U 标签("pythön.org")。

如果服务器名称上存在解码错误,则 TLS 连接将以向 Client 端发送ALERT_DESCRIPTION_INTERNAL_ERROR致命 TLS 警报消息的方式终止。

3.4 版的新Function。

  • SSLContext. load_dh_params(* dhfile *)
    • 加载用于 Diffie-Hellman(DH)密钥交换的密钥生成参数。使用 DH 密钥交换可以提高前向保密性,但会浪费计算资源(包括服务器和 Client 端上的计算资源)。 * dhfile *参数应该是包含 PEM 格式的 DH 参数的文件的路径。

此设置不适用于 Client 端套接字。您也可以使用OP_SINGLE_DH_USE选项进一步提高安全性。

版本 3.3 中的新Function。

  • SSLContext. set_ecdh_curve(曲线名称)
    • 设置基于椭圆曲线的 Diffie-Hellman(ECDH)密钥交换的曲线名称。 ECDH 明显快于常规 DH,同时可以说是安全的。 * curve_name *参数应该是描述众所周知的椭圆曲线的字符串,例如prime256v1表示广泛支持的曲线。

此设置不适用于 Client 端套接字。您也可以使用OP_SINGLE_ECDH_USE选项进一步提高安全性。

如果HAS_ECDHFalse,则此方法不可用。

版本 3.3 中的新Function。

See also

  • 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是一个布尔值,它标识此套接字是否需要服务器端或 Client 端行为。

对于 Client 端套接字,上下文构造是延迟的。如果尚未连接基础套接字,则将在套接字上调用connect()之后执行上下文构造。对于服务器端套接字,如果该套接字没有远程对等方,则假定它是侦听套接字,并且对passaccept()方法接受的 Client 端连接自动执行服务器端 SSL 包装。该方法可能会引发SSLError

在 Client 端连接上,可选参数* server_hostname 指定我们要连接到的服务的主机名。这使得单个服务器可以使用不同的证书托管多个基于 SSL 的服务,这与 HTTP 虚拟主机非常相似。如果 server_side 为 true,则指定 server_hostname *将引发ValueError

参数do_handshake_on_connect指定是在执行socket.connect()之后自动进行 SSL 握手,还是pass调用SSLSocket.do_handshake()方法来使应用程序显式调用它。显式调用SSLSocket.do_handshake()可使程序控制握手中涉及的套接字 I/O 的阻塞行为。

参数suppress_ragged_eofs指定SSLSocket.recv()方法应如何从连接的另一端发出意外的 EOFsignal。如果指定为True(默认值),它会响应来自底层套接字的意外 EOF 错误而返回正常的 EOF(空字节对象)。如果False,它将引发异常返回给调用者。

在版本 3.5 中更改:即使 OpenSSL 没有 SNI,也始终允许传递 server_hostname。

在版本 3.6 中更改:添加了* session *参数。

在 3.7 版中进行了更改:该方法在SSLContext.sslsocket_class实例而不是硬编码的SSLSocket上返回。

3.7 版中的新Function。

  • SSLContext. wrap_bio(传入传出,* server_side = False server_hostname = None session = None *)
    • 包装 BIO 对象传入传出并返回SSLContext.sslobject_class的实例(默认为SSLObject)。 SSL 例程将从传入的 BIO 读取 Importing 数据,并将数据写入传出的 BIO。

在版本 3.6 中更改:添加了* session *参数。

在 3.7 版中进行了更改:该方法在SSLContext.sslobject_class实例而不是硬编码的SSLObject上返回。

3.7 版中的新Function。

  • SSLContext. session_stats ( )
    • 获取有关此上下文创建或 Management 的 SSL 会话的统计信息。返回一个字典,该字典将每个一点信息的名称 Map 为其数值。例如,以下是自创建上下文以来会话缓存中的命中总数和未命中总数:
>>> stats = context.session_stats()
>>> stats['hits'], stats['misses']
(0, 0)

Example:

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 版的新Function。

在版本 3.7 中更改:启用主机名检查并且verify_modeCERT_NONE时,verify_mode现在自动更改为CERT_REQUIRED。以前,相同的操作会因ValueError而失败。

Note

此Function需要 OpenSSL 0.9.8f 或更高版本。

  • SSLContext. keylog_filename
    • 每当生成或接收密钥材料时,请将 TLS 密钥写入密钥日志文件。 keylog 文件仅用于调试目的。文件格式由 NSS 指定,并由许多流量分析器(例如 Wireshark)使用。日志文件以仅追加模式打开。写入在线程之间同步,但在进程之间不同步。

3.8 版的新Function。

Note

此Function需要 OpenSSL 1.1.1 或更高版本。

属性maximum_versionminimum_versionSSLContext.options都影响上下文的受支持的 SSL 和 TLS 版本。该实现不防止无效组合。例如,在options中的OP_NO_TLSv1_2maximum_version设置为TLSVersion.TLSv1_2的上下文将无法构建 TLS 1.2 连接。

Note

除非使用 OpenSSL 1.1.0g 或更高版本编译 ssl 模块,否则此属性不可用。

3.7 版中的新Function。

Note

除非使用 OpenSSL 1.1.0g 或更高版本编译 ssl 模块,否则此属性不可用。

3.7 版中的新Function。

  • SSLContext. num_tickets
    • 控制TLS_PROTOCOL_SERVER上下文的 TLS 1.3 会话票证的数量。该设置对 TLS 1.0 到 1.2 连接没有影响。

Note

除非使用 OpenSSL 1.1.1 或更高版本编译 ssl 模块,否则此属性不可用。

3.8 版的新Function。

  • SSLContext. options
    • 一个整数,表示在此上下文中启用的 SSL 选项集。默认值为OP_ALL,但是您可以pass对它们进行“或”运算来指定其他选项,例如OP_NO_SSLv2

Note

对于低于 0.9.8m 的 OpenSSL 版本,只能设置选项,而不能清除它们。try清除选项(pass重置相应的位)将引发ValueError

在版本 3.6 中更改:SSLContext.options返回Options标志:

>>> ssl.create_default_context().options  
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
  • SSLContext. post_handshake_auth
    • 启用 TLS 1.3 握手后 Client 端身份验证。默认情况下,握手后身份验证是禁用的,并且服务器只能在初始握手期间请求 TLSClient 端证书。启用后,服务器可以在握手后的任何时间请求 TLSClient 端证书。

在 Client 端套接字上启用后,Client 端会向服务器发送 signal,通知它支持握手后身份验证。

在服务器端套接字上启用时,SSLContext.verify_mode也必须设置为CERT_OPTIONALCERT_REQUIRED。实际的 Client 端证书交换将延迟到调用SSLSocket.verify_client_post_handshake()并执行某些 I/O 为止。

Note

仅在启用 OpenSSL 1.1.1 和 TLS 1.3 的情况下可用。如果没有 TLS 1.3 支持,则属性值为“无”,无法修改

3.8 版的新Function。

  • SSLContext. protocol

    • 构造上下文时选择的协议版本。此属性是只读的。
  • SSLContext. hostname_checks_common_name

    • 缺少主题备用名称 extensions 时,check_hostname是否回退以验证证书的主题公用名(默认值:true)。

Note

仅可使用 OpenSSL 1.1.0 或更高版本编写。

3.7 版中的新Function。

  • SSLContext. verify_flags
    • 证书验证操作的标志。您可以pass对它们进行“或”操作来设置VERIFY_CRL_CHECK_LEAF之类的标志。默认情况下,OpenSSL 既不需要也不验证证书吊销列表(CRL)。仅适用于 openssl 0.9.8 版。

3.4 版的新Function。

在版本 3.6 中更改:SSLContext.verify_flags返回VerifyFlags标志:

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

在版本 3.6 中更改:SSLContext.verify_mode返回VerifyMode枚举:

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

Certificates

证书通常是公钥/私钥系统的一部分。在这个系统中,每个* principal (可能是一台机器,一个人或一个组织)都分配有一个唯一的两部分式加密密钥。密钥的一部分是公共的,称为“公共密钥”;另一部分被保密,称为私钥*。这两个部分是相关的,如果您用其中一个部分对消息进行加密,则可以使用另一部分对消息进行解密,而使用另一部分来“仅**”进行解密。

证书包含有关两个主体的信息。它包含* subject 的名称和主题的公钥。它还包含第二个负责人 issuer *的语句,主题是他们声称的身份,而这确实是主题的公钥。发行人的语句使用发行人的私钥签名,只有发行人才知道。但是,任何人都可以pass找到发行者的公钥,解密该语句并将其与证书中的其他信息进行比较来验证发行者的语句。该证书还包含有关其有效期限的信息。这表示为两个字段,称为“ notBefore”和“ notAfter”。

在使用证书的 Python 中,Client 端或服务器可以使用证书来证明其身份。还可能需要网络连接的另一端来生成证书,并且可以对证书进行验证,以使需要这种验证的 Client 端或服务器满意。如果验证失败,可以将连接try设置为引发异常。验证由底层的 OpenSSL 框架自动完成;该应用程序无需关注其机制。但是应用程序通常确实需要提供证书集以允许此过程发生。

Python 使用文件包含证书。它们的格式应为“ PEM”(请参见 RFC 1422),这是一种以 64 位编码的形式,其中包含标题行和页脚行:

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

Certificate chains

包含证书的 Python 文件可以包含一系列证书,有时也称为证书链。该链应从“是”Client 端或服务器的委托人的特定证书开始,然后是该证书的颁发者的证书,然后是“那个”证书的颁发者的证书,依此类推。直到您获得自签名的证书,即具有相同主题和颁发者的证书,有时也称为* root 证书*。证书应仅在证书文件中串联在一起。例如,假设我们具有三个证书链,从我们的服务器证书到签署我们的服务器证书的证书颁发机构的证书,再到颁发证书颁发机构的证书的代理机构的根证书:

-----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 certificates

如果您需要验证连接证书的另一端,则需要提供一个“ CA certs”文件,其中包含您愿意信任的每个颁发者的证书链。同样,此文件仅包含这些串联在一起的链。为了进行验证,Python 将使用它在文件中找到的匹配的第一条链。可以pass调用SSLContext.load_default_certs()使用平台的证书文件,该操作passcreate_default_context()自动完成。

组合的密钥和证书

通常,私钥与证书存储在同一文件中。在这种情况下,仅需要传递SSLContext.load_cert_chain()wrap_socket()certfile参数。如果私钥与证书一起存储,则它应位于证书链中的第一个证书之前:

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

Self-signed certificates

如果要创建提供 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
%

自签名证书的缺点是它是自己的根证书,没有其他人将其保存在已知(和受信任)根证书的缓存中。

Examples

测试 SSL 支持

要测试 Python 安装中是否存在 SSL 支持,用户代码应使用以下习惯用法:

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

Client-side operation

本示例使用建议的 Client 端套接字安全设置(包括自动证书验证)创建 SSL 上下文:

>>> context = ssl.create_default_context()

如果您希望自己调整安全设置,则可以从头开始创建上下文(但是请注意,您可能无法正确获得设置):

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

(此代码段假定您的 os 将所有 CA 证书 Binding 在/etc/ssl/certs/ca-bundle.crt中;否则,您将得到一个错误,必须调整位置)

PROTOCOL_TLS_CLIENT协议为证书验证和主机名验证配置上下文。 verify_mode设置为CERT_REQUIRED,而check_hostname设置为True。所有其他协议都会使用不安全的默认值创建 SSL 上下文。

当您使用上下文连接到服务器时,CERT_REQUIREDcheck_hostname验证服务器证书:它确保使用 CA 证书之Pair服务器证书进行签名,检查签名的正确性,并验证其他属性,例如证书的有效性和身份。主机名:

>>> 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 通道并验证了证书,您可以 continue 与服务器对话:

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

请参阅下面对Security considerations的讨论。

Server-side operation

对于服务器操作,通常您需要在文件中具有服务器证书和私钥。首先,您将创建一个包含密钥和证书的上下文,以便 Client 端可以检查您的真实性。然后,您将打开一个套接字,将其绑定到端口,在其上调用listen(),然后开始 awaitClient 端连接:

import socket, ssl

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")

bindsocket = socket.socket()
bindsocket.bind(('myaddr.mydomain.com', 10023))
bindsocket.listen(5)

Client 端连接后,您将在套接字上调用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中读取数据并对其进行处理,直到完成 Client 端操作(或 Client 端操作完成)为止:

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

然后返回侦听新的 Client 端连接(当然,true 的服务器可能会在单独的线程中处理每个 Client 端连接,或者将套接字放在non-blocking mode并使用事件循环)。

有关非阻塞套接字的说明

SSL 套接字在非阻塞模式下的行为与常规套接字略有不同。使用非阻塞套接字时,因此需要注意以下几点:

在版本 3.5 中进行了更改:在早期的 Python 版本中,SSLSocket.send()方法返回零,而不是引发SSLWantWriteErrorSSLWantReadError

  • 调用select()可以告诉您可以从 OS 套接字读取(或写入),但这并不意味着在 SSL 上层有足够的数据。例如,可能只有一部分 SSL 帧到达。因此,您必须准备处理SSLSocket.recv()SSLSocket.send()故障,并在再次调用select()之后重试。

  • 相反,由于 SSL 层具有其自己的框架,因此 SSL 套接字可能仍具有可供读取的数据,而无需select()意识到。因此,您应该首先调用SSLSocket.recv()以清空所有潜在的可用数据,然后仅在必要时才阻塞select()调用。

(当然,在使用其他 Primitives(例如poll()selectors模块中的 Primitives)时,也适用类似的规定)

  • SSL 握手本身将是非阻塞的:必须重试SSLSocket.do_handshake()方法,直到它成功返回。这是使用select()await 套接字准备就绪的摘要:
while True:
    try:
        sock.do_handshake()
        break
    except ssl.SSLWantReadError:
        select.select([sock], [], [])
    except ssl.SSLWantWriteError:
        select.select([], [sock], [])

See also

asyncio模块支持无阻塞 SSL 套接字并提供更高级别的 API。它使用selectors模块轮询事件,并处理SSLWantWriteErrorSSLWantReadErrorBlockingIOError异常。它也异步运行 SSL 握手。

内存 BIO 支持

3.5 版中的新Function。

自从 Python 2.6 中引入 SSL 模块以来,SSLSocket类提供了两个相关但截然不同的Function区域:

  • SSL 协议处理

  • Network IO

网络 IO API 与socket.socket提供的相同,SSLSocket也从中继承。这样就可以将 SSL 套接字用作常规套接字的替代产品,从而很容易为现有应用程序添加 SSL 支持。

将 SSL 协议处理和网络 IO 结合使用通常效果很好,但是在某些情况下则不行。一个示例是异步 IO 框架,该框架要使用与socket.socket和内部 OpenSSL 套接字 IO 例程假定的“文件 Descriptors 上的选择/轮询”(基于就绪)模型不同的 IO 多路复用模型。这与该模型效率不高的 Windows 之类的平台最相关。为此,提供了称为SSLObjectSSLSocket范围缩小的变体。

  • 类别 ssl. SSLObject
    • 范围缩小的变体SSLSocket表示不包含任何网络 IO 方法的 SSL 协议实例。此类通常由希望pass内存缓冲区为 SSL 实现异步 IO 的框架作者使用。

此类在 OpenSSL 所实现的低级 SSL 对象之上实现接口。该对象捕获 SSL 连接的状态,但不提供任何网络 IO 本身。 IO 需要pass单独的“ BIO”对象执行,这些对象是 OpenSSL 的 IO 抽象层。

此类没有公共构造函数。必须使用wrap_bio()方法创建一个SSLObject实例。此方法将创建SSLObject实例并将其绑定到Pair BIO。 “传入” BIO 用于将数据从 Python 传递到 SSL 协议实例,而“传出” BIO 用于以其他方式传递数据。

可以使用以下方法:

SSLSocket相比,此对象缺少以下Function:

  • 任何形式的网络 IO; recv()send()仅读取和写入基础MemoryBIO缓冲区。

  • 没有* do_handshake_on_connect *机制。您必须始终手动呼叫do_handshake()来开始握手。

  • 没有处理* suppress_ragged_eofs *。passSSLEOFError异常报告所有违反协议的文件结束条件。

  • 方法unwrap()调用不返回任何内容,与 SSL 套接字不同,它返回基础套接字。

  • 传递给SSLContext.set_servername_callback()的* server_name_callback *回调将获得SSLObject实例而不是SSLSocket实例作为其第一个参数。

一些与SSLObject的使用有关的 Comments:

在 3.7 版中进行了更改:SSLObject实例必须使用wrap_bio()创建。在早期版本中,可以直接创建实例。从未记录或得到官方支持。

SSLObject 使用内存缓冲区与外界通信。 MemoryBIO类提供了可用于此目的的内存缓冲区。它包装一个 OpenSSL 内存 BIO(基本 IO)对象:

  • 类别 ssl. MemoryBIO

    • 一个内存缓冲区,可用于在 Python 和 SSL 协议实例之间传递数据。
  • pending

    • 返回当前在内存缓冲区中的字节数。
  • eof

    • 指示内存 BIO 在文件末尾位置是否为当前的布尔值。
  • read(* n = -1 *)

    • 从内存缓冲区读取最多* n 个字节。如果未指定 n *或为负,则返回所有字节。
  • write(* buf *)

    • 将* buf *中的字节写入内存 BIO。 * buf *参数必须是支持缓冲区协议的对象。

返回值是写入的字节数,该字节数始终等于* buf *的长度。

  • write_eof ( )
    • 将 EOF 标记写入内存 BIO。调用此方法后,调用write()是非法的。读取缓冲区中当前的所有数据后,属性eof将变为 true。

SSL session

3.6 版的新Function。

  • 类别 ssl. SSLSession

  • id

  • time

  • timeout

  • ticket_lifetime_hint

  • has_ticket

Security considerations

Best defaults

对于 Client 端使用 ,如果您对安全策略没有任何特殊要求,则强烈建议您使用create_default_context()函数来创建 SSL 上下文。它将加载系统的受信任 CA 证书,启用证书验证和主机名检查,并try选择合理的安全协议和密码设置。

例如,这是使用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')

如果连接需要 Client 端证书,则可以使用SSLContext.load_cert_chain()添加。

相反,如果您pass自己调用SSLContext构造函数来创建 SSL 上下文,则默认情况下不会启用证书验证或主机名检查。如果这样做,请阅读以下段落以达到良好的安全级别。

Manual settings

Verifying certificates

直接调用SSLContext构造函数时,默认为CERT_NONE。由于它不对另一个对等方进行身份验证,因此它可能是不安全的,尤其是在 Client 端模式下,在大多数情况下,您希望确保与之对话的服务器的真实性。因此,在 Client 端模式下,强烈建议使用CERT_REQUIRED。但是,这本身是不够的。您还必须检查可以pass调用SSLSocket.getpeercert()获得的服务器证书是否与所需服务匹配。对于许多协议和应用程序,可以pass主机名来标识服务;在这种情况下,可以使用match_hostname()Function。启用SSLContext.check_hostname时,将自动执行此通用检查。

在版本 3.7 中更改:主机名匹配现在由 OpenSSL 执行。 Python 不再使用match_hostname()

在服务器模式下,如果要使用 SSL 层(而不是使用更高级别的身份验证机制)对 Client 端进行身份验证,则还必须指定CERT_REQUIRED并类似地检查 Client 端证书。

Protocol versions

SSL 版本 2 和 3 被认为是不安全的,因此有使用危险。如果要在 Client 端和服务器之间获得最大的兼容性,建议使用PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER作为协议版本。默认情况下禁用 SSLv2 和 SSLv3.

>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.options |= ssl.OP_NO_TLSv1
>>> client_context.options |= ssl.OP_NO_TLSv1_1

上面创建的 SSL 上下文仅允许 TLSv1.2 和更高版本(如果系统支持)连接到服务器。 PROTOCOL_TLS_CLIENT表示默认情况下证书验证和主机名检查。您必须将证书加载到上下文中。

Cipher selection

如果您有高级安全性要求,则可以passSSLContext.set_ciphers()方法对在 SSL 会话进行协商时启用的密码进行微调。从 Python 3.2.3 开始,ssl 模块默认禁用某些弱密码,但是您可能希望进一步限制密码的选择。确保阅读有关密码列表格式的 OpenSSL 文档。如果要检查给定密码列表启用了哪些密码,请在系统上使用SSLContext.get_ciphers()openssl ciphers命令。

Multi-processing

如果将此模块用作多进程应用程序的一部分(例如,使用multiprocessingconcurrent.futures模块),请注意 OpenSSL 的内部随机数生成器无法正确处理派生的进程。如果应用程序对os.fork()使用任何 SSL Function,则它们必须更改父进程的 PRNG 状态。 RAND_add()RAND_bytes()RAND_pseudo_bytes()的任何成功调用就足够了。

TLS 1.3

3.7 版中的新Function。

Python 对带有 OpenSSL 1.1.1 的 TLS 1.3 具有临时和实验性的支持。新协议的行为与以前版本的 TLS/SSL 略有不同。某些新的 TLS 1.3 Function尚不可用。

  • TLS 1.3 使用一组不同的密码套件。默认情况下,所有 AES-GCM 和 ChaCha20 密码套件都是启用的。方法SSLContext.set_ciphers()尚无法启用或禁用任何 TLS 1.3 密码,但是SSLContext.get_ciphers()返回它们。

  • 会话票证不再作为初始握手的一部分发送,并且以不同的方式处理。 SSLSocket.sessionSSLSession与 TLS 1.3 不兼容。

  • 初始握手期间也不再验证 Client 端证书。服务器可以随时请求证书。Client 端在从服务器发送或接收应用程序数据时处理证书请求。

  • 尚不支持 TLS 1.3 Function,如早期数据,延迟的 TLSClient 端证书请求,签名算法配置和重新生成密钥。

LibreSSL support

LibreSSL 是 OpenSSL 1.0.1 的分支。 ssl 模块对 LibreSSL 的支持有限。使用 LibreSSL 编译 ssl 模块时,某些Function不可用。