ssl ---用于套接字对象的TLS/SSL封装器

源代码: Lib/ssl.py


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

注解

有些行为可能依赖于平台,因为调用操作系统套接字API。安装的openssl版本也可能导致行为的变化。例如,tlsv1.1和tlsv1.2附带了openssl版本1.0.1。

警告

在未阅读 安全注意事项 . 这样做可能导致错误的安全感,因为SSL模块的默认设置不一定适合您的应用程序。

本节记录了 ssl 模块;有关TLS、SSL和证书的更多一般信息,读者可以参考底部“另见”部分中的文档。

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

对于更复杂的应用程序, ssl.SSLContext 类帮助管理设置和证书,然后通过 SSLContext.wrap_socket() 方法。

在 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。

函数、常量和异常

套接字创建

由于python 3.2和2.7.9,建议使用 SSLContext.wrap_socket() 一个 SSLContext 将套接字封装为的实例 SSLSocket 物体。帮助程序的功能 create_default_context() 返回具有安全默认设置的新上下文。老年人 wrap_socket() 函数不推荐使用,因为它效率低下,不支持服务器名称指示(sni)和主机名匹配。

具有默认上下文和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())

侦听本地主机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 具有给定的默认设置的对象 目的 . 设置由 ssl 模块,通常表示比调用 SSLContext 直接构造函数。

卡菲尔卡普斯卡塔塔 表示要信任以进行证书验证的可选CA证书,如 SSLContext.load_verify_locations() . 如果这三个都是 None ,此函数可以选择信任系统的默认CA证书。

设置为: PROTOCOL_TLSOP_NO_SSLv2OP_NO_SSLv3 高加密密码套件,无RC4,无未经认证的密码套件。经过 SERVER_AUTH 作为 目的 集合 verify_modeCERT_REQUIRED 或者加载CA证书(当 卡菲尔卡普斯卡塔塔 被给予)或使用 SSLContext.load_default_certs() 加载默认CA证书。

什么时候? keylog_filename 支持和环境变量 SSLKEYLOGFILE 已设置, create_default_context() 启用密钥日志记录。

注解

协议、选项、密码和其他设置可以随时更改为更严格的值,而无需预先取消预测。这些值代表了兼容性和安全性之间的公平平衡。

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

注解

如果您发现某些较旧的客户端或服务器尝试与 SSLContext 由这个函数创建,它们得到一个错误,说明“协议或密码组不匹配”,可能它们只支持ssl3.0,这个函数排除了使用 OP_NO_SSLv3 . SSL3.0被广泛认为是 completely broken . 如果您仍然希望继续使用此功能,但仍允许SSL 3.0连接,则可以使用以下方法重新启用它们:

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

3.4 新版功能.

在 3.4.4 版更改: RC4已从默认密码字符串中删除。

在 3.6 版更改: 已将chacha20/poly1305添加到默认密码字符串中。

3des已从默认密码字符串中删除。

在 3.8 版更改: 支持密钥登录到 SSLKEYLOGFILE 加入。

例外情况

exception ssl.SSLError

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

在 3.3 版更改: SSLError 以前是 socket.error .

library

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

3.3 新版功能.

reason

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

3.3 新版功能.

exception ssl.SSLZeroReturnError

一个子类 SSLError 在尝试读取或写入并且SSL连接已完全关闭时引发。注意,这并不意味着底层传输(read-tcp)已经关闭。

3.3 新版功能.

exception ssl.SSLWantReadError

一个子类 SSLError 由A提出 non-blocking SSL socket 当尝试读取或写入数据时,但在满足请求之前,需要在底层TCP传输上接收更多数据。

3.3 新版功能.

exception ssl.SSLWantWriteError

一个子类 SSLError 由A提出 non-blocking SSL socket 当尝试读取或写入数据时,但在满足请求之前,需要在底层TCP传输上发送更多数据。

3.3 新版功能.

exception ssl.SSLSyscallError

一个子类 SSLError 尝试在SSL套接字上完成操作时遇到系统错误时引发。不幸的是,没有简单的方法来检查原始的errno编号。

3.3 新版功能.

exception ssl.SSLEOFError

一个子类 SSLError 在突然终止SSL连接时引发。通常,遇到此错误时不应尝试重用基础传输。

3.3 新版功能.

exception ssl.SSLCertVerificationError

一个子类 SSLError 在证书验证失败时引发。

3.7 新版功能.

verify_code

表示验证错误的数字错误号。

verify_message

验证错误的可读字符串。

exception ssl.CertificateError

的别名 SSLCertVerificationError .

在 3.7 版更改: 异常现在是的别名 SSLCertVerificationError .

随机生成

ssl.RAND_bytes(num)

返回 num 加密的强伪随机字节。提出一个 SSLError 如果prng的种子中没有足够的数据,或者当前rand方法不支持该操作。 RAND_status() 可用于检查PRNG和 RAND_add() 可以用来播种。

几乎所有应用程序 os.urandom() 优先考虑。

阅读维基百科的文章, Cryptographically secure pseudorandom number generator (CSPRNG) ,以获得加密强生成器的要求。

3.3 新版功能.

ssl.RAND_pseudo_bytes(num)

返回(bytes,is_cryptographic):字节为 num 伪随机字节,is_cryptographic is True 如果生成的字节是加密的强字节。提出一个 SSLError 如果当前rand方法不支持该操作。

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

几乎所有应用程序 os.urandom() 优先考虑。

3.3 新版功能.

3.6 版后已移除: openssl已弃用 ssl.RAND_pseudo_bytes() 使用 ssl.RAND_bytes() 相反。

ssl.RAND_status()

返回 True 如果SSL伪随机数生成器的种子具有“足够”的随机性,并且 False 否则。你可以使用 ssl.RAND_egd()ssl.RAND_add() 增加伪随机数发生器的随机性。

ssl.RAND_egd(path)

如果您在某处运行一个熵收集守护进程(egd),并且 path 是对其开放的套接字连接的路径名,这将从套接字中读取256字节的随机性,并将其添加到SSL伪随机数生成器中,以提高生成的密钥的安全性。这通常只在没有更好的随机性来源的系统上是必要的。

有关熵收集守护进程的源,请参阅http://egd.sourceforge.net/或http://prngd.sourceforge.net/。

Availability :不适用于libressl和openssl>1.1.0。

ssl.RAND_add(bytes, entropy)

混合给定 字节 进入ssl伪随机数生成器。参数 (float)是字符串中包含的熵的下限(因此您可以始终使用 0.0 )见 RFC 1750 有关熵源的更多信息。

在 3.5 版更改: 可写的 bytes-like object 现在被接受。

证书处理

ssl.match_hostname(cert, hostname)

验证 cert (以解码格式返回 SSLSocket.getpeercert() )与给定的匹配 主机名 . 应用的规则是用于检查HTTPS服务器标识的规则,如中所述。 RFC 2818RFC 5280RFC 6125 . 除了https之外,此函数还应该适用于检查各种基于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 新版功能.

在 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 版更改: 此函数不再用于TLS连接。主机名匹配现在由openssl执行。

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

3.7 版后已移除.

ssl.cert_time_to_seconds(cert_time)

返回以秒为单位的时间,给定 cert_time 表示中证书的“NotBefore”或“NotAfter”日期的字符串 "%b %d %H:%M:%S %Y %Z" strptime格式(C语言环境)。

下面是一个例子:

>>> import ssl
>>> timestamp = ssl.cert_time_to_seconds("Jan  5 09:34:43 2018 GMT")
>>> timestamp  
1515144883
>>> from datetime import datetime
>>> print(datetime.utcfromtimestamp(timestamp))  
2018-01-05 09:34:43

“NotBefore”或“NotAfter”日期必须使用GMT (RFC 5280

在 3.5 版更改: 将输入时间解释为输入字符串中“gmt”时区指定的UTC时间。以前使用过本地时区。返回一个整数(输入格式中没有小数点)

ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)

给出了地址 addr 一个受SSL保护的服务器,作为( 主机名port-number )配对,获取服务器的证书,并将其作为PEM编码字符串返回。如果 ssl_version 指定,使用该版本的SSL协议尝试连接到服务器。如果 ca_certs 如果指定,则它应该是一个包含根证书列表的文件,格式与中的同一参数使用的格式相同。 SSLContext.wrap_socket() . 调用将尝试根据该组根证书验证服务器证书,如果验证尝试失败,则调用将失败。

在 3.3 版更改: 此功能现在与IPv6兼容。

在 3.5 版更改: 默认值 ssl_version 从变 PROTOCOL_SSLv3PROTOCOL_TLS 与现代服务器的最大兼容性。

ssl.DER_cert_to_PEM_cert(DER_cert_bytes)

将证书作为一个der编码的字节块,返回同一证书的pem编码字符串版本。

ssl.PEM_cert_to_DER_cert(PEM_cert_string)

给定一个作为ASCIIPEM字符串的证书,返回同一证书的一个DER编码的字节序列。

ssl.get_default_verify_paths()

返回一个命名元组,其中包含到OpenSSL的默认cafile和capath的路径。路径与使用的路径相同 SSLContext.set_default_verify_paths() . 返回值为 named tuple DefaultVerifyPaths

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

  • capath -到capath或的解析路径 None 如果目录不存在,

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

  • openssl_cafile -硬编码到cafile的路径,

  • openssl_capath_env -OpenSSL的环境密钥指向一个capath,

  • openssl_capath -到capath目录的硬编码路径

Availability :libressl忽略环境变量 openssl_cafile_envopenssl_capath_env .

3.4 新版功能.

ssl.enum_certificates(store_name)

从Windows的系统证书存储中检索证书。 store_name 可能是其中之一 CAROOTMY . Windows也可能提供其他证书存储。

函数返回(cert_bytes,encoding_type,trust)元组的列表。编码类型指定证书字节的编码。要么是 x509_asn 对于X.509 ASN.1数据或 pkcs_7_asn 对于PKCS 7 ASN.1数据。信任将证书的用途指定为一组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)]

Availability :Windows。

3.4 新版功能.

ssl.enum_crls(store_name)

从Windows的系统证书存储中检索CRL。 store_name 可能是其中之一 CAROOTMY . Windows也可能提供其他证书存储。

函数返回(cert_bytes,encoding_type,trust)元组的列表。编码类型指定证书字节的编码。要么是 x509_asn 对于X.509 ASN.1数据或 pkcs_7_asn 对于PKCS 7 ASN.1数据。

Availability :Windows。

3.4 新版功能.

ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)

举个例子 sock 属于 socket.socket ,并返回 ssl.SSLSocket ,的子类型 socket.socket ,它将底层套接字封装在SSL上下文中。 sock 必须是 SOCK_STREAM 套接字;不支持其他套接字类型。

在内部,函数创建一个 SSLContext 用协议 ssl_versionSSLContext.options 设置为 cert_reqs . 中频参数 关键文件证书文件ca_certs密码 设置,然后将值传递给 SSLContext.load_cert_chain()SSLContext.load_verify_locations()SSLContext.set_ciphers() .

参数 server_sidedo_handshake_on_connectsuppress_ragged_eofs 含义与 SSLContext.wrap_socket() .

3.7 版后已移除: 由于python 3.2和2.7.9,建议使用 SSLContext.wrap_socket() 而不是 wrap_socket() . 顶级函数是有限的,它创建了一个不安全的客户端套接字,没有服务器名称指示或主机名匹配。

常量

所有常量现在都是 enum.IntEnumenum.IntFlag 收藏。

3.6 新版功能.

ssl.CERT_NONE

可能的值 SSLContext.verify_mode ,或者 cert_reqs 参数到 wrap_socket() .除了 PROTOCOL_TLS_CLIENT ,这是默认模式。对于客户端套接字,几乎可以接受任何证书。验证错误(如不可信或过期的证书)将被忽略,并且不会中止TLS/SSL握手。

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

参见 安全注意事项 下面。

ssl.CERT_OPTIONAL

可能的值 SSLContext.verify_mode ,或者 cert_reqs 参数到 wrap_socket() . 在客户端模式下, CERT_OPTIONAL 含义与 CERT_REQUIRED . 建议使用 CERT_REQUIRED 而不是客户端套接字。

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

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

ssl.CERT_REQUIRED

可能的值 SSLContext.verify_mode ,或者 cert_reqs 参数到 wrap_socket() . 在这种模式下,需要来自套接字连接另一端的证书;一个 SSLError 如果没有提供证书或验证失败,将引发。这种模式是 not 足以在客户端模式下验证证书,因为它与主机名不匹配。 check_hostname 还必须启用以验证证书的真实性。 PROTOCOL_TLS_CLIENT 使用 CERT_REQUIRED 使能 check_hostname 默认情况下。

对于服务器套接字,此模式提供强制的TLS客户端证书身份验证。将向客户端发送客户端证书请求,客户端必须提供有效且可信的证书。

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

class ssl.VerifyMode

enum.IntEnum cert_x常量集合。

3.6 新版功能.

ssl.VERIFY_DEFAULT

可能的值 SSLContext.verify_flags . 在此模式下,不检查证书吊销列表(CRL)。默认情况下,openssl不需要也不验证crl。

3.4 新版功能.

ssl.VERIFY_CRL_CHECK_LEAF

可能的值 SSLContext.verify_flags . 在此模式下,只检查对等证书,而不检查中间CA证书。该模式需要由对等证书的颁发者(其直接祖先CA)签名的有效CRL。如果没有正确的CRL加载 SSLContext.load_verify_locations ,验证将失败。

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_X509_TRUSTED_FIRST

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

3.4.4 新版功能.

class ssl.VerifyFlags

enum.IntFlag verify_*常量的集合。

3.6 新版功能.

ssl.PROTOCOL_TLS

选择客户端和服务器都支持的最高协议版本。尽管有这个名称,但是这个选项可以同时选择“ssl”和“tls”协议。

3.6 新版功能.

ssl.PROTOCOL_TLS_CLIENT

自动协商最高协议版本,如 PROTOCOL_TLS ,但只支持客户端 SSLSocket 连接。协议启用 CERT_REQUIREDcheck_hostname 默认情况下。

3.6 新版功能.

ssl.PROTOCOL_TLS_SERVER

自动协商最高协议版本,如 PROTOCOL_TLS ,但仅支持服务器端 SSLSocket 连接。

3.6 新版功能.

ssl.PROTOCOL_SSLv23

Alias PROTOCOL_TLS .

3.6 版后已移除: 使用 PROTOCOL_TLS 相反。

ssl.PROTOCOL_SSLv2

选择ssl版本2作为通道加密协议。

如果使用 OPENSSL_NO_SSL2 flag。

警告

SSL版本2不安全。它的使用是非常不鼓励的。

3.6 版后已移除: openssl已经删除了对sslv2的支持。

ssl.PROTOCOL_SSLv3

选择ssl版本3作为通道加密协议。

如果使用 OPENSSL_NO_SSLv3 flag。

警告

SSL版本3不安全。它的使用是非常不鼓励的。

3.6 版后已移除: OpenSSL已弃用所有特定于版本的协议。使用默认协议 PROTOCOL_TLS 像flag一样 OP_NO_SSLv3 相反。

ssl.PROTOCOL_TLSv1

选择TLS版本1.0作为通道加密协议。

3.6 版后已移除: OpenSSL已弃用所有特定于版本的协议。使用默认协议 PROTOCOL_TLS 像flag一样 OP_NO_SSLv3 相反。

ssl.PROTOCOL_TLSv1_1

选择TLS版本1.1作为通道加密协议。仅适用于OpenSSL 1.0.1+版本。

3.4 新版功能.

3.6 版后已移除: OpenSSL已弃用所有特定于版本的协议。使用默认协议 PROTOCOL_TLS 像flag一样 OP_NO_SSLv3 相反。

ssl.PROTOCOL_TLSv1_2

选择TLS版本1.2作为通道加密协议。这是最现代的版本,如果双方都能说出来,这可能是最大限度保护的最佳选择。仅适用于OpenSSL 1.0.1+版本。

3.4 新版功能.

3.6 版后已移除: OpenSSL已弃用所有特定于版本的协议。使用默认协议 PROTOCOL_TLS 像flag一样 OP_NO_SSLv3 相反。

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_versionSSLContext.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或更高版本。当根据旧版本的openssl编译python时,标志默认为 0 .

3.7 新版功能.

3.7 版后已移除: 由于openssl 1.1.0,该选项已弃用。它被添加到2.7.15、3.6.3和3.7.0中,以实现与OpenSSL 1.0.2的向后兼容性。

ssl.OP_NO_RENEGOTIATION

禁用tlsv1.2及更早版本中的所有重新协商。不要发送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通道的压缩。如果应用程序协议支持其自己的压缩方案,这将非常有用。

此选项仅适用于OpenSSL 1.0.0及更高版本。

3.3 新版功能.

class ssl.Options

enum.IntFlag 运算常数集合。

ssl.OP_NO_TICKET

防止客户端请求会话票证。

3.6 新版功能.

ssl.HAS_ALPN

OpenSSL库是否内置了对 Application-Layer Protocol Negotiation 如中所述的TLS扩展 RFC 7301 .

3.5 新版功能.

ssl.HAS_NEVER_CHECK_COMMON_NAME

openssl库是否有内置支持,不检查主题公用名和 SSLContext.hostname_checks_common_name 是可写的。

3.7 新版功能.

ssl.HAS_ECDH

openssl库是否内置了对基于椭圆曲线的diffie-hellman密钥交换的支持。这应该是正确的,除非分发服务器显式禁用了该功能。

3.3 新版功能.

ssl.HAS_SNI

OpenSSL库是否内置了对 服务器名称指示 扩展(定义见 RFC 6066

3.2 新版功能.

ssl.HAS_NPN

OpenSSL库是否内置了对 下一个协议协商 如中所述 Application Layer Protocol Negotiation . 如果为真,则可以使用 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.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 Alert Registry 包含此列表和对定义其含义的RFC的引用。

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

3.4 新版功能.

class ssl.AlertDescription

enum.IntEnum 警报描述常数集合。

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_x常量的集合。

3.6 新版功能.

class ssl.TLSVersion

enum.IntEnum 的SSL和TLS版本集合 SSLContext.maximum_versionSSLContext.minimum_version .

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。

SSL套接字

class ssl.SSLSocket(socket.socket)

SSL套接字提供以下方法 套接字对象

然而,由于ssl(和tls)协议在TCP之上有自己的框架,因此ssl套接字抽象在某些方面可能与普通OS级套接字的规范不同。尤其是看到 notes on non-blocking sockets .

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

在 3.5 版更改: 这个 sendfile() 方法已添加。

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

3.6 版后已移除: 不推荐创建 SSLSocket 直接实例,使用 SSLContext.wrap_socket() 把Socket包起来。

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

SSL套接字还具有以下附加方法和属性:

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

读到 len 来自SSL套接字的字节数据,并将结果作为 bytes 实例。如果 缓冲区 指定,然后改为读取缓冲区,并返回读取的字节数。

提高 SSLWantReadErrorSSLWantWriteError 如果Socket是 non-blocking 阅读会被屏蔽。

因为在任何时候都有可能进行重新谈判, read() 也可能导致写入操作。

在 3.5 版更改: 每次接收或发送字节时,套接字超时不再重置。套接字超时现在为要读取的最大总持续时间 len 字节。

3.6 版后已移除: 使用 recv() 而不是 read() .

SSLSocket.write(buf)

buf 并返回写入的字节数。这个 buf 参数必须是支持缓冲区接口的对象。

提高 SSLWantReadErrorSSLWantWriteError 如果Socket是 non-blocking 写会被阻止。

因为在任何时候都有可能进行重新谈判, write() 也可能导致读取操作。

在 3.5 版更改: 每次接收或发送字节时,套接字超时不再重置。套接字超时现在为要写入的最大总持续时间 buf .

3.6 版后已移除: 使用 send() 而不是 write() .

注解

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

通常,您应该使用像 recv()send() 而不是这些方法。

SSLSocket.do_handshake()

执行SSL设置握手。

在 3.4 版更改: 握手方法也执行 match_hostname()check_hostname 套接字的属性 context 是真的。

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

在 3.7 版更改: 在握手过程中,主机名或IP地址与openssl匹配。函数 match_hostname() 不再使用。如果openssl拒绝主机名或IP地址,则提前中止握手,并向对等端发送一条TLS警报消息。

SSLSocket.getpeercert(binary_form=False)

如果连接的另一端没有对等机的证书,则返回 None .如果尚未完成SSL握手,请提高 ValueError .

如果 binary_form 参数是 False ,并且从对等方接收到证书,此方法返回 dict 实例。如果未验证证书,则dict为空。如果证书经过验证,它将返回一个包含多个密钥的dict,其中包括 subject (签发证书的负责人)和 issuer (签发证书的负责人)。如果证书包含 使用者替代名称 延伸部分(参见 RFC 3280 )还有一个 subjectAltName 输入字典。

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

注解

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

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

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

  • 对于服务器SSL套接字,客户机仅在服务器请求时提供证书;因此 getpeercert() 将返回 None 如果你用过 CERT_NONE (而不是 CERT_OPTIONALCERT_REQUIRED

在 3.2 版更改: 返回的词典包含其他项,如 issuernotBefore .

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

在 3.9 版更改: IPv6地址字符串不再有尾随的新行。

SSLSocket.cipher()

返回一个三值元组,该元组包含正在使用的密码的名称、定义其使用的SSL协议的版本以及正在使用的秘密位的数目。如果未建立连接,则返回 None .

SSLSocket.shared_ciphers()

返回在握手过程中客户端共享的密码列表。返回列表的每个条目都是一个三值元组,其中包含密码的名称、定义其使用的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 名单。当前仅“tls unique”通道绑定,由定义 RFC 5929 ,支持。 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 新版功能.

SSLSocket.unwrap()

执行ssl关闭握手,从基础套接字中删除tls层,并返回基础套接字对象。这可用于从通过连接进行的加密操作转到未加密。返回的套接字应始终用于与连接的另一侧进行进一步通信,而不是用于原始套接字。

SSLSocket.verify_client_post_handshake()

从TLS 1.3客户端请求握手后身份验证(PHA)。只有在最初的TLS握手之后,并且在两侧启用了PHA的情况下,才能从服务器端套接字为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

这个 SSLContext 此SSL套接字所绑定的对象。如果使用弃用的 wrap_socket() 功能(而不是 SSLContext.wrap_socket() ,这是为此SSL套接字创建的自定义上下文对象。

3.2 新版功能.

SSLSocket.server_side

布尔值,即 True 用于服务器端Socket和 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

这个 SSLSession 对于此SSL连接。在执行了TLS握手之后,该会话可用于客户端和服务器端套接字。对于客户端套接字,可以在 do_handshake() 已调用以重用会话。

3.6 新版功能.

SSLSocket.session_reused

3.6 新版功能.

SSL上下文

3.2 新版功能.

ssl上下文比单个ssl连接保存各种数据的时间更长,例如ssl配置选项、证书和私钥。它还管理服务器端套接字的SSL会话缓存,以加速来自同一客户端的重复连接。

class ssl.SSLContext(protocol=PROTOCOL_TLS)

创建新的SSL上下文。你可以通过 协议 那一定是 PROTOCOL_* 此模块中定义的常量。参数指定要使用的SSL协议版本。通常,服务器选择特定的协议版本,客户机必须适应服务器的选择。大多数版本与其他版本不可互操作。如果未指定,则默认值为 PROTOCOL_TLS ;它提供了与其他版本的最大兼容性。

下面是一个表,显示客户端(向下)中的哪些版本可以连接到服务器中的哪些版本(沿顶部):

客户机 / 服务器

SSLv2

SSLv3

TLS 3

TLSv1

TLSv1.1

TLSv1.2

SSLV2

1

SSLV3

2

TLSSSLV233

1

2

TLVS1

TLSv1.1

TLSv1.2

脚注

1(1,2)

SSLContext 禁用sslv2 OP_NO_SSLv2 默认情况下。

2(1,2)

SSLContext 禁用SSLv3 OP_NO_SSLv3 默认情况下。

3(1,2)

TLS 1.3协议可用于 PROTOCOL_TLS 在openssl中>=1.1.1。只有TLS 1.3没有专用的协议常量。

参见

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

在 3.6 版更改: 使用安全的默认值创建上下文。选项 OP_NO_COMPRESSIONOP_CIPHER_SERVER_PREFERENCEOP_SINGLE_DH_USEOP_SINGLE_ECDH_USEOP_NO_SSLv2 (除 PROTOCOL_SSLv2OP_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 新版功能.

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

加载私钥和相应的证书。这个 证书文件 字符串必须是包含证书的PEM格式的单个文件的路径,以及建立证书真实性所需的任何数量的CA证书。这个 关键文件 字符串(如果存在)必须指向包含中的私钥的文件。否则,私钥将从 证书文件 也。参见 证书 有关如何将证书存储在 证书文件 .

这个 密码 参数可以是一个函数来调用以获取用于解密私钥的密码。只有加密了私钥并且需要密码时才会调用它。调用它时不带参数,它应该返回一个字符串、字节或字节数组。如果返回值是字符串,则在使用它解密密钥之前,它将被编码为UTF-8。或者,字符串、字节或字节数组值可以直接作为 密码 参数。如果私钥未加密且不需要密码,则将忽略此项。

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

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

在 3.3 版更改: 新建可选参数 密码 .

SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)

从默认位置加载一组默认的“证书颁发机构”(CA)证书。在Windows上,它从 CAROOT 系统存储。在它调用的其他系统上 SSLContext.set_default_verify_paths() . 将来,该方法也可能从其他位置加载CA证书。

这个 目的 标志指定加载哪种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 . 至少其中之一 卡菲尔卡普斯 必须指定。

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

这个 卡菲尔 字符串(如果存在)是以PEM格式连接的CA证书文件的路径。参见 证书 有关如何排列此文件中的证书的详细信息。

这个 卡普斯 字符串(如果存在)是一个目录的路径,该目录包含多个PEM格式的CA证书,后跟 OpenSSL specific layout .

这个 卡塔塔 对象(如果存在)是一个或多个PEM编码证书的ASCII字符串或 bytes-like object 对DER编码的证书。就像 卡普斯 忽略PEM编码证书周围的额外行,但必须至少存在一个证书。

在 3.4 版更改: 新建可选参数 卡塔塔

SSLContext.get_ca_certs(binary_form=False)

获取已加载的“证书颁发机构”(CA)证书的列表。如果 binary_form 参数是 False 每个列表条目都是一个dict,就像 SSLSocket.getpeercert() . 否则,该方法返回一个由DER编码的证书列表。返回的列表不包含来自的证书 卡普斯 除非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()  # 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 新版功能.

SSLContext.set_default_verify_paths()

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

SSLContext.set_ciphers(ciphers)

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

注解

连接后, SSLSocket.cipher() ssl sockets方法将提供当前选定的密码。

openssl 1.1.1默认情况下启用了tls 1.3密码套件。套房不能禁用 set_ciphers() .

SSLContext.set_alpn_protocols(protocols)

指定在SSL/TLS握手期间套接字应公布的协议。它应该是一个ASCII字符串列表,比如 ['http/1.1', 'spdy/2'] ,按优先顺序排列。协议的选择将在握手过程中进行,并将根据 RFC 7301 . 成功握手后, SSLSocket.selected_alpn_protocol() 方法将返回商定的协议。

这种方法会提高 NotImplementedError 如果 HAS_ALPNFalse .

openssl 1.1.0到1.1.0e将中止握手并引发 SSLError 当双方都支持ALPN,但不能就协议达成一致时。1.1.0f+的行为类似于1.0.2, SSLSocket.selected_alpn_protocol() 没有返回。

3.5 新版功能.

SSLContext.set_npn_protocols(protocols)

指定在SSL/TLS握手期间套接字应公布的协议。它应该是一个字符串列表,比如 ['http/1.1', 'spdy/2'] ,按优先顺序排列。协议的选择将在握手过程中进行,并将根据 Application Layer Protocol Negotiation . 成功握手后, SSLSocket.selected_npn_protocol() 方法将返回商定的协议。

这种方法会提高 NotImplementedError 如果 HAS_NPNFalse .

3.3 新版功能.

SSLContext.sni_callback

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

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

将使用三个参数调用回调函数;第一个参数是 ssl.SSLSocket ,第二个是一个字符串,表示客户机要通信的服务器名称(或 None 如果tls客户机hello不包含服务器名称),则第三个参数是原始参数 SSLContext . 服务器名称参数为文本。对于国际化域名,服务器名称是IDN A-Label ("xn--pythn-mua.org"

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

由于TLS连接的早期协商阶段,只有有限的方法和属性可用,例如 SSLSocket.selected_alpn_protocol()SSLSocket.context . SSLSocket.getpeercert()SSLSocket.getpeercert()SSLSocket.cipher()SSLSocket.compress() 方法要求TLS连接的进展超过了TLS客户端hello,因此将不包含返回的有意义的值,也无法安全地调用这些值。

这个 sni_callback 函数必须返回 None 允许TLS协商继续。如果需要TLS故障,则常量 ALERT_DESCRIPTION_* 可以退货。其他返回值将导致与 ALERT_DESCRIPTION_INTERNAL_ERROR .

如果从中引发异常 sni_callback 函数TLS连接将以致命的TLS警报消息终止 ALERT_DESCRIPTION_HANDSHAKE_FAILURE .

这种方法会提高 NotImplementedError 如果openssl库在构建时定义了openssl_no_tlsext。

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密钥交换提高了前向保密性,同时牺牲了计算资源(在服务器和客户机上)。这个 DHFLASH 参数应该是包含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_ECDHFalse .

3.3 新版功能.

参见

SSL/TLS & Perfect Forward Secrecy

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 指定要连接的服务的主机名。这允许单个服务器使用不同的证书托管多个基于SSL的服务,与HTTP虚拟主机非常相似。指定 server_hostname 将提高 ValueError 如果 server_side 是真的。

参数 do_handshake_on_connect 指定在执行 socket.connect() 或者应用程序是否通过调用 SSLSocket.do_handshake() 方法。调用 SSLSocket.do_handshake() 显式地给程序控制握手中涉及的套接字I/O的阻塞行为。

参数 suppress_ragged_eofs 指定 SSLSocket.recv() 方法应该从连接的另一端发出意外的EOF信号。如果指定为 True (默认值),它返回一个正常的eof(空字节对象),以响应从基础套接字引发的意外eof错误;如果 False ,它将把异常返回给调用方。

阶段session .

在 3.5 版更改: 始终允许传递服务器主机名,即使openssl没有sni。

在 3.6 版更改: 阶段 已添加参数。

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

包裹生物对象 进来的外向的 并返回 SSLContext.sslobject_class (默认) SSLObject )。SSL例程将从传入的BIO读取输入数据,并将数据写入传出的BIO。

这个 server_sideserver_hostname阶段 参数的含义与中的相同 SSLContext.wrap_socket() .

在 3.6 版更改: 阶段 已添加参数。

在 3.7 版更改: 方法返回的实例 SSLContext.sslobject_class 而不是硬编码 SSLObject .

SSLContext.sslobject_class

返回类型 SSLContext.wrap_bio() 默认为 SSLObject . 可以在类的实例上重写该属性,以便返回的自定义子类 SSLObject .

3.7 新版功能.

SSLContext.session_stats()

获取有关此上下文创建或管理的SSL会话的统计信息。返回一个字典,其中映射了每个 piece of information 它们的数值。例如,这里是自创建上下文以来会话缓存中命中和未命中的总数:

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

是否将对等证书的主机名与匹配 match_hostname() 在里面 SSLSocket.do_handshake() . 语境 verify_mode 必须设置为 CERT_OPTIONALCERT_REQUIRED ,你必须通过 server_hostnamewrap_socket() 以匹配主机名。启用主机名检查自动设置 verify_modeCERT_NONECERT_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_REQUIRED 当启用主机名检查时,并且 verify_modeCERT_NONE . 以前相同的操作会失败,因为 ValueError .

注解

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

SSLContext.keylog_filename

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

3.8 新版功能.

注解

此功能需要OpenSSL 1.1.1或更高版本。

SSLContext.maximum_version

A TLSVersion 表示支持的最高TLS版本的枚举成员。值默认为 TLSVersion.MAXIMUM_SUPPORTED . 对于协议以外的其他协议,该属性是只读的 PROTOCOL_TLSPROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER .

属性 maximum_versionminimum_versionSSLContext.options 所有这些都会影响上下文的受支持的SSL和TLS版本。实现不会阻止无效的组合。例如,上下文 OP_NO_TLSv1_2 在里面 optionsmaximum_version 设置为 TLSVersion.TLSv1_2 将无法建立TLS 1.2连接。

注解

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

3.7 新版功能.

SSLContext.minimum_version

类似于 SSLContext.maximum_version 但它是支持的最低版本或 TLSVersion.MINIMUM_SUPPORTED .

注解

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

3.7 新版功能.

SSLContext.num_tickets

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

注解

除非使用openssl 1.1.1或更新版本编译SSL模块,否则此属性不可用。

3.8 新版功能.

SSLContext.options

表示在此上下文上启用的一组SSL选项的整数。默认值为 OP_ALL ,但可以指定其他选项,例如 OP_NO_SSLv2 把它们捆在一起。

注解

对于0.9.8M以上的OpenSSL版本,只能设置选项,而不能清除它们。试图清除选项(通过重置相应的位)将引发 ValueError .

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

>>> 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握手后客户端身份验证。默认情况下,后握手身份验证被禁用,并且服务器只能在初始握手期间请求一个TLS客户端证书。启用后,服务器可以在握手后随时请求TLS客户端证书。

当在客户端套接字上启用时,客户端向服务器发出信号,表示它支持握手后身份验证。

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

注解

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

3.8 新版功能.

SSLContext.protocol

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

SSLContext.hostname_checks_common_name

是否 check_hostname 在没有主题备用名称扩展名的情况下返回以验证证书的主题公用名(默认值:true)。

注解

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

3.7 新版功能.

SSLContext.security_level

表示 security level 对于上下文。此属性是只读的。

Availability :OpenSSL 1.1.0或更新版本

3.10 新版功能.

SSLContext.verify_flags

证书验证操作的标志。您可以设置如下标志 VERIFY_CRL_CHECK_LEAF 把它们捆在一起。默认情况下,openssl不需要也不验证证书吊销列表(crls)。仅适用于OpenSSL版本0.9.8+。

3.4 新版功能.

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

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

是否尝试验证其他对等方的证书以及验证失败时如何操作。此属性必须是 CERT_NONECERT_OPTIONALCERT_REQUIRED .

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

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

证书

证书通常是公钥/私钥系统的一部分。在这个系统中,每个 主要的 ,(可能是机器、个人或组织)被分配一个唯一的两部分加密密钥。密钥的一部分是公共的,称为 公钥 ;另一部分是保密的,称为 私钥 . 这两个部分是相关的,因为如果用其中一个部分加密消息,那么可以用另一个部分对其进行解密,并且 only 另一部分。

证书包含有关两个主体的信息。它包含一个 主题 以及主题的公钥。它还包含第二个主体的声明,即 发行人 ,主题是他们声称的对象,这确实是主题的公钥。发行人的声明是用发行人的私钥签署的,只有发行人知道这一点。但是,任何人都可以通过查找颁发者的公钥、用它解密语句以及将其与证书中的其他信息进行比较来验证颁发者的语句。证书还包含有关其有效期的信息。这表示为两个字段,分别称为“NotBefore”和“NotAfter”。

在使用证书的Python中,客户机或服务器可以使用证书来证明它们是谁。网络连接的另一端也可以被要求生成一个证书,并且可以对该证书进行验证,使需要进行验证的客户机或服务器满意。如果验证失败,可以将连接尝试设置为引发异常。验证是通过底层的OpenSSL框架自动完成的;应用程序不需要关心其机制。但是应用程序通常需要提供一组证书来允许进行此过程。

python使用文件来包含证书。它们应该格式化为“pem”(请参见 RFC 1422 ,它是一个以base-64编码的表单,用标题行和脚注行封装:

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

证书链

包含证书的python文件可以包含一系列证书,有时称为 证书链 . 这个链应该从“是”客户机或服务器的主体的特定证书开始,然后是该证书的颁发者的证书,然后是 that 证书,等等,直到你得到一个证书 self-signed 即具有相同主题和颁发者的证书,有时称为 根证书 . 证书应该在证书文件中连接在一起。例如,假设我们有三个证书链,从服务器证书到签署服务器证书的证书颁发机构的证书,再到颁发证书颁发机构证书的机构的根证书:

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

组合密钥和证书

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

-----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_REQUIREDcheck_hostname 设置为 True . 所有其他协议都创建具有不安全默认值的SSL上下文。

使用上下文连接到服务器时, CERT_REQUIREDcheck_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.mydomain.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

回到监听新的客户机连接(当然,真正的服务器可能会在一个单独的线程中处理每个客户机连接,或者将套接字放入 non-blocking mode 并使用事件循环)。

非阻塞Socket注意事项

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

  • 大多数 SSLSocket 方法将引发 SSLWantWriteErrorSSLWantReadError 而不是 BlockingIOError 如果I/O操作会阻塞。 SSLWantReadError 如果需要对基础套接字执行读取操作,则将引发;并且 SSLWantWriteError 对基础套接字执行写操作。注意尝试 到SSL套接字可能需要 阅读 首先从底层套接字,并尝试 read 从SSL套接字可能需要 到基础套接字。

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

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

  • 相反,由于ssl层有自己的帧,因此ssl套接字可能仍然有可供读取的数据,而没有 select() 意识到这一点。因此,你应该先调用 SSLSocket.recv() 排出任何可能可用的数据,然后只阻止 select() 如有必要,请致电。

    (当然,在使用诸如 poll() 或者那些在 selectors 模块)

  • SSL握手本身将是非阻塞的: SSLSocket.do_handshake() 方法必须重试,直到成功返回。这是一个使用 select() 等待Socket准备就绪:

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

参见

这个 asyncio 模块支持 non-blocking SSL sockets 并提供更高级别的API。它使用 selectors 模块和手柄 SSLWantWriteErrorSSLWantReadErrorBlockingIOError 例外情况。它还异步运行SSL握手。

记忆生物支持

3.5 新版功能.

自从在python 2.6中引入ssl模块以来, SSLSocket 类提供了两个相关但不同的功能领域:

  • SSL协议处理

  • 网络IO

网络IO API与 socket.socket ,从中 SSLSocket 也继承。这允许将SSL套接字用作常规套接字的内嵌替换,从而很容易向现有应用程序添加SSL支持。

将ssl协议处理和网络IO结合起来通常会很好地工作,但在某些情况下却不行。例如,异步IO框架希望使用不同的IO多路复用模型,而不是“在文件描述符上选择/轮询”(基于就绪度)模型,该模型由 socket.socket 以及通过内部openssl套接字IO例程。这主要与Windows等平台相关,因为在这些平台上,此模型不高效。为此,缩小了 SSLSocket 调用 SSLObject 提供。

class ssl.SSLObject

缩小范围的变种 SSLSocket 表示不包含任何网络IO方法的SSL协议实例。此类通常由框架作者使用,他们希望通过内存缓冲区为SSL实现异步IO。

这个类在一个低级的ssl对象上实现了一个由openssl实现的接口。此对象捕获SSL连接的状态,但不提供任何网络IO本身。IO需要通过单独的“bio”对象来执行,这些对象是OpenSSL的IO抽象层。

此类没有公共构造函数。安 SSLObject 必须使用创建实例 wrap_bio() 方法。此方法将创建 SSLObject 实例并将其绑定到一对BIOS。这个 进来的 bio用于将数据从python传递到ssl协议实例,而 外向的 bio用于以另一种方式传递数据。

可以使用以下方法:

与…相比 SSLSocket ,此对象缺少以下功能:

  • 任何形式的网络IO; recv()send() 只读写底层 MemoryBIO 缓冲器。

  • 没有 do_handshake_on_connect 机械。您必须始终手动调用 do_handshake() 开始握手。

  • 无法处理 suppress_ragged_eofs . 所有违反协议的文件结束条件都通过 SSLEOFError 例外。

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

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

关于使用 SSLObject

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

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

class ssl.MemoryBIO

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

pending

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

eof

一个布尔值,指示内存bio在文件结束位置是否为当前状态。

read(n=- 1)

读到 n 来自内存缓冲区的字节。如果 n 未指定或为负,将返回所有字节。

write(buf)

从中写入字节 buf 去记忆生物。这个 buf 参数必须是支持缓冲区协议的对象。

返回值是写入的字节数,它始终等于 buf .

write_eof()

写一个EOF标记到内存BIO。调用此方法后,调用 write() . 属性 eof 将在读取缓冲区中当前所有数据后变为真。

SSL会话

3.6 新版功能.

class ssl.SSLSession

会话对象由使用 session .

id
time
timeout
ticket_lifetime_hint
has_ticket

安全注意事项

最佳默认值

为了 客户使用 如果您的安全策略没有任何特殊要求,强烈建议您使用 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 构造函数本身,默认情况下它不会启用证书验证和主机名检查。如果您这样做,请阅读下面的段落以达到良好的安全级别。

手动设置

正在验证证书

当调用 SSLContext 直接建造商, CERT_NONE 是默认值。因为它不认证另一个对等端,所以它可能是不安全的,特别是在客户机模式下,在大多数情况下,您希望确保您所交谈的服务器的真实性。因此,在客户机模式下,强烈建议使用 CERT_REQUIRED . 但是,这本身是不够的;您还必须检查服务器证书,该证书可以通过调用 SSLSocket.getpeercert() ,与所需服务匹配。对于许多协议和应用程序,可以通过主机名来标识服务;在这种情况下,可以通过 match_hostname() 可以使用函数。当 SSLContext.check_hostname 启用。

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

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

协议版本

SSL版本2和3被认为是不安全的,因此使用起来很危险。如果希望客户端和服务器之间的最大兼容性,建议使用 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 默认情况下表示证书验证和主机名检查。您必须将证书加载到上下文中。

密码选择

如果您有高级安全要求,则可以通过 SSLContext.set_ciphers() 方法。从python 3.2.3开始,ssl模块默认禁用某些弱密码,但您可能希望进一步限制密码的选择。一定要阅读OpenSSL关于 cipher list format . 如果要检查给定密码列表启用的密码,请使用 SSLContext.get_ciphers()openssl ciphers 系统上的命令。

多处理

如果将此模块用作多处理应用程序的一部分(例如,使用 multiprocessingconcurrent.futures 模块),请注意OpenSSL的内部随机数生成器不能正确处理复刻进程。如果应用程序将任何SSL功能用于 os.fork() .任何成功的调用 RAND_add()RAND_bytes()RAND_pseudo_bytes() 就足够了。

TLS 1.3

3.7 新版功能.

python对使用openssl 1.1.1的tls 1.3提供了临时和实验支持。新协议的行为与以前版本的tls/ssl略有不同。一些新的TLS 1.3功能尚不可用。

  • TLS 1.3使用一组分离的密码套件。默认情况下,所有aes-gcm和chacha20密码套件都启用。方法 SSLContext.set_ciphers() 还不能启用或禁用任何TLS 1.3密码,但是 SSLContext.get_ciphers() 归还他们。

  • 会话通知单不再作为初始握手的一部分发送,处理方式也不同。 SSLSocket.sessionSSLSession 与TLS 1.3不兼容。

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

  • 还不支持诸如早期数据、延迟的TLS客户端证书请求、签名算法配置和重新键入等TLS 1.3功能。

libressl支持

libressl是openssl 1.0.1的一个分支。SSL模块对libressl的支持有限。当使用libressl编译ssl模块时,某些功能不可用。