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

源代码: Lib / ssl.py

 


此模块提供对传输层安全性的访问(通常称为“SecureSockets Layer”网络套接字的加密和对等认证工具,包括客户端和服务器端。该模块使用OpenSSLlibrary。只要在该平台上安装了OpenSSL,它就可以在所有现代Unix系统,Windows,Mac OS X和可能的其他平台上使用.

注意

某些行为可能与平台有关,因为调用操作系统套接字API。安装的OpenSSL版本也可能导致行为的变化。例如,TL​​Sv1.1和TLSv1.2带有开放版本1.0.1.

Warning

不使用此模块而不读取安全注意事项。做得太糟糕会导致错误的安全感,因为thessl模块的默认设置不一定适合您的应用程序.

本节介绍了ssl模块;有关TLS,SSL和证书的更多信息,读者可以参考底部“另请参见”部分中的文档.

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

对于更复杂的应用程序,ssl.SSLContextclasshelps管理设置和证书,然后可以通过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.

FunctionsConstants和Exceptions

套接字创建

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

侦听localhost的服务器套接字示例IPv4:

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('/path/to/certchain.pem', '/path/to/private.key')

with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
    sock.bind(('127.0.0.1', 8443))
    sock.listen(5)
    with context.wrap_socket(sock, server_side=True) as ssock:
        conn, addr = ssock.accept()
        ...

上下文创建

便利功能有助于为共同目的创建SSLContext对象.

ssl.create_default_context (purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)
返回新的SSLContext具有给定purpose。设置由ssl模块选择,通常比直接调用SSLContext构造函数表示更高的安全级别.

cafile, capath, cadata代表证书验证的可选CA证书,如SSLContext.load_verify_locations()。如果这三个都是None,则此函数可以选择信任系统的defaultCA证书.

设置为:PROTOCOL_TLS, OP_NO_SSLv2OP_NO_SSLv3具有高加密密码套件,没有RC4,没有未经验证的密码套件。通过SERVER_AUTH purpose设置verify_modeCERT_REQUIRED并加载CA证书(当给出cafile, capathcadata中的至少一个时)或使用SSLContext.load_default_certs()加载默认CA证书.

注意

协议,选项,密码和其他设置可以随时更改为更严格的值,而无需事先弃用。这些价值观代表了兼容性和安全性之间的公平平衡.

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

注意

如果您发现当某些旧客户端或服务器尝试连接时SSLContext由这个函数创建,他们得到错误的“协议或密码套件不匹配”,可能是他们只支持SSL3.0这个功能排除使用OP_NO_SSLv3。SSL3.0被广泛认为是完全破碎的。如果您仍希望继续使用此功能但仍允许SSL 3.0连接,则可以使用以下命令重新启用它们:

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

版本3.4.

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

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

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

Exceptions

exception ssl.SSLError
引发信号从基础SSL实现(当前由OpenSSL库提供)发出错误。这表示在基础网络连接上存在的更高级别的加密和认证层中存在一些问题。这个错误是OSErrorSSLError实例的错误代码和消息由OpenSSL库提供.

在版本3.3中更改:SSLError曾经是socket.error.

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

新版本3.3.

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

3.3版本中的新功能

exception ssl.SSLZeroReturnError
的子类SSLError尝试读取或写入时提出并且SSL连接已完全关闭。请注意,这并不意味着底层传输(读取TCP)已关闭.

新版本3.3.

exception ssl.SSLWantReadError
的子类SSLError由提出无阻塞SSL插座尝试读取或写入数据时,在完成请求之前需要在底层TCP传输上接收更多数据.

3.3版本中的新功能

exception ssl.SSLWantWriteError
的子类SSLError在尝试读取或写入数据时由非阻塞SSL套接字引发,但是在请求可以填充之前需要在底层TCP传输上发送更多数据.

3.3版本中的新功能

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

新版本3.3.

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

新版本3.3.

exception ssl.SSLCertVerificationError
当证书验证失败时,SSLError的子类被引发

新版本3.7.

verify_code
表示验证错误的数字错误编号.
verify_message
一个人类可读的验证错误字符串
exception ssl.CertificateError
//别的SSLCertVerificationError.

在版本3.7中更改:异常现在是SSLCertVerificationError.

的别名随机生成

ssl.RAND_bytesnum
返回num加密强伪随机字节。如果PRNG没有播种足够的数据或者当前RAND方法不支持操作,则提高SSLErrorRAND_status()可以用来检查PRNG的状态和RAND_add()可以用来种PRNG.

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

阅读Wikipedia文章,Cryptographically secure伪随机数生成器(CSPRNG),以获得加密生成器的要求.

新版本3.3.

ssl.RAND_pseudo_bytes (num
返回(bytes,is_cryptographic):字节是num伪随机字节,如果生成的字节是加密的,则is_cryptographic是True。如果当前RAND方法不支持该操作,则引发SSLError .

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

对于几乎所有应用程序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_egdpath
如果你在某个地方运行熵聚集守护进程(EGD),path是打开它的套接字连接的路径名,这将从套接字读取256字节的随机性,并将其添加到SSL伪随机数生成器以增加生成的密钥的安全性。这通常只适用于没有更好随机性的系统.

请参阅http://egd.sourceforge.net/或http://prngd.sourceforge.net/获取熵收集守护进程的来源.

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

ssl.RAND_add(bytes, entropy)
将给定的bytes混合到SSL伪随机数生成器中。参数entropy(浮点数)是包含instring的熵的下限(所以你总是可以使用0.0)。见 RFC 1750 有关熵源的更多信息.

版本3.5:可写字节对象现已被接受.

证书处理

ssl.match_hostnamecert, hostname
验证cert(以SSLSocket.getpeercert()返回的解码格式)匹配给定的hostname。应用的规则是用于检查HTTPS服务器身份的规则,如 RFC 2818 , RFC 5280 RFC 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节并且在国际化域名(IDN)片段内没有匹配多个通配符(例如*.*.com*a*.example.org)nora通配符.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)
返回自Epoch以来的秒数,给定cert_time字符串表示来自"%b %d %H:%M:%S %Y %Z" strptime格式(Clocale)的acertificate的“notBefore”或“notAfter”日期.

这里是一个例子:

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

“notBefore”或“notAfter”日期必须使用GMT( RFC 5280 ).

在版本3.5中更改:将输入时间解释为UTC中由输入字符串中的’GMT’timezone指定的时间。以前使用过当地时区。返回一个整数(输入格式中没有一秒的分数)

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

在版本3.3中更改:此功能现在与IPv6兼容.

更改版本3.5:默认ssl_versionPROTOCOL_SSLv3更改为PROTOCOL_TLS,以便与现代服务器最大程度地兼容.

ssl.DER_cert_to_PEM_certDER_cert_bytes
将证书作为DER编码的字节blob,返回相同证书的PEM-encodedstring版本.
ssl.PEM_cert_to_DER_certPEM_cert_string
将证书作为ASCII PEM字符串,返回同一证书的DER编码的字节序列.
ssl.get_default_verify_paths ( )
返回一个带有OpenSSL默认cafile和capath路径的命名元组。路径与SSLContext.set_default_verify_paths()使用的路径相同。返回值为名为tuple DefaultVerifyPaths

  • cafile – 解析到cafile的路径或None如果文件不存在,
  • capath – 解析到capath的路径或None如果目录不存在,
  • openssl_cafile_env– OpenSSL的环境密钥,指向一个咖啡馆,
  • openssl_cafile – 硬编码到咖啡馆的路径,
  • openssl_capath_env – OpenSSL的环境密钥,指向一个capath,
  • openssl_capath – 硬编码路径到一个capath目录

可用性:LibreSSL忽略环境变量openssl_cafile_envopenssl_capath_env.

版本3.4.

ssl.enum_certificates(store_name)
从Windows的系统证书库中检索证书。store_name可能是CA, ROOTMY。Windows也可以提供额外的证书存储.

该函数返回(cert_bytes,encoding_type,trust)元组的列表.coding_type指定cert_bytes的编码。这是x509_asn对于X.509 ASN.1数据或pkcs_7_asnforPKCS#7 ASN.1数据。Trust将证书的目的指定为一组OIDS或正好True如果证书对所有目的都值得信赖.

例:

>>> ssl.enum_certificates("CA")
[(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}),
 (b'data...', 'x509_asn', True)]

可用性:Windows.

新版本3.4.

ssl.enum_crls(store_name)
从Windows系统证书商店中获取CRL。store_name可能是CA, ROOTMY。Windows也可以提供额外的证书存储.

该函数返回(cert_bytes,encoding_type,trust)元组的列表.coding_type指定cert_bytes的编码。这是x509_asn对于X.509 ASN.1数据或pkcs_7_asn forPKCS#7 ASN.1数据

Availability:Windows.

新版本3.4。

ssl.wrap_socketsock, 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.SSLSocketsocket.socket的子类型,它包含SSL上下文中的底层套接字sock必须是SOCK_STREAM插座;其他套接字类型不受支持.

在内部,函数用协议SSLContext创建一个ssl_versionSSLContext.options调成 cert_reqs。ifparameters 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()。顶级功能是有限的,并创建一个不安全的客户端套接字,没有服务器名称指示或主机名匹配.

Constants

所有常量现在enum.IntEnumenum.IntFlag集合.

新版本3.6.

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

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

参见讨论安全考虑下面

ssl.CERT_OPTIONAL
// SSLContext.verify_mode的可能值,或cert_reqs参数wrap_socket()。在客户端模式下,CERT_OPTIONALCERT_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。这个模式是不是足以在客户端模式下验证证书asit不匹配主机名。check_hostname也必须能够验证证书的真实性.PROTOCOL_TLS_CLIENT使用CERT_REQUIRED andenables check_hostname默认情况下

使用服务器套接字,此模式提供强制性TLS客户端证书身份验证。客户端证书请求被发送到客户端,客户端必须提供有效且可信的证书.

使用此设置需要通过一组有效的CA证书,或者SSLContext.load_verify_locations()或者作为avalueca_certs参数wrap_socket().

class ssl.VerifyMode
enum.IntEnum收集CERT_ *常量

新版本3.6.

ssl.VERIFY_DEFAULT
SSLContext.verify_flags的可能值在此模式下,不检查证书重定位列表(CRL)。默认情况下,OpenSSL既不需要也不验证CRL。

新版本3.4.

ssl.VERIFY_CRL_CHECK_LEAF
SSLContext.verify_flags的可能值。在此模式下,仅检查同一个证书,但不检查中间CA证书。该模式需要由对等证书颁发者(其directancestor CA)签署的有效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的可能值它在构建信任链以验证acertificate时指示OpenSSL toprefer可信证书。默认情况下启用此标志.

版本3.4.4.

class ssl.VerifyFlags
enum.IntFlagVERIFY_ *常量的集合

版本3.6.

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

新版本3.6.

ssl.PROTOCOL_TLS_CLIENT
自动协商最高协议版本,如PROTOCOL_TLS,但仅支持客户端SSLSocket连接。protocolenables CERT_REQUIREDcheck_hostname bydefault.

新版本3.6.

ssl.PROTOCOL_TLS_SERVER
自动协商最高协议版本如PROTOCOL_TLS,但只支持服务器端SSLSocket connections.

新版本3.6.

ssl.PROTOCOL_SSLv23
Alias for data: PROTOCOL_TLS .

从版本3.6开始不推荐使用:使用PROTOCOL_TLS代替

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

如果OpenSSL是,则该协议不可用用OPENSSL_NO_SSL2 flag.

警告

SSL版本2不安全。它的使用非常气馁.

自版本3.6以来被删除: OpenSSL已经取消了对SSLv2的支持.

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

如果使用OPENSSL_NO_SSLv3标志编译OpenSSL,则该协议不可用.

Warning

SSL版本3不安全。它的使用非常气馁.

自版本3.6以来已经删除: OpenSSL已经弃用了所有特定版本的协议。使用默认协议PROTOCOL_TLSOP_NO_SSLv3之类的标志代替

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

自版本3.6以来重新编写:OpenSSL已弃用所有特定于版本的协议。使用defaultprotocol PROTOCOL_TLSOP_NO_SSLv3等标志.

ssl.PROTOCOL_TLSv1_1
选择TLS版本1.1作为通道加密协议。只能使用openssl版本1.0.1 +。

版本3.4.

新版自版本3.6:OpenSSL已弃用所有特定于版本的协议。使用defaultprotocol PROTOCOL_TLSOP_NO_SSLv3等标志.

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

版本3.4.

中的新功能自版本3.6以来已删除: OpenSSL已弃用所有特定于版本的协议。使用defaultprotocol PROTOCOL_TLSOP_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作为协议版本。OpenSSL 1.1.1或更高版本提供TLS 1.3。当Python针对旧版本的OpenSSL编译时,标志默认为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通道上的压缩。如果applicationprotocol支持自己的压缩方案,这很有用.

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

3.3版本中的新功能

class ssl.Options
enum.IntFlag收集OP_ *常量
ssl.OP_NO_TICKET
防止客户端请求会话票据

新版本3.6.

ssl.HAS_ALPN
OpenSSL库是否内置支持Application-LayerProtocol NegotiationRFC 7301 .

版本3.5中的新功能

ssl.HAS_NEVER_CHECK_COMMON_NAME
OpenSSL库是否内置支持不检查subjectcommon名称和SSLContext.hostname_checks_common_name iswriteable.

新版本3.7.

ssl.HAS_ECDH
OpenSSL库是否内置支持Elliptic Curve-basedDiffie-Hellman密钥交换。这应该是真的,除非经销商明确禁用该功能.

3.3版本中的新功能

ssl.HAS_SNI
OpenSSL库是否内置支持Server NameIndication扩展(在中定义)RFC 6066 ).

版本3.2.

ssl.HAS_NPN
OpenSSL库是否内置了对Next ProtocolNegotiation的支持,如应用层协议协商中所述。如果是,你可以使用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_NUMBER268443839
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
"0x100020bf"

版本3.2.

ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE
ssl.ALERT_DESCRIPTION_INTERNAL_ERROR
ALERT_DESCRIPTION_*
来自的警报描述RFC 5246 和别的。IANA TLS警报注册表包含此列表以及对其含义进行定义的RFC的引用.

用作SSLContext.set_servername_callback().

版本3.4.

class ssl.AlertDescription
enum.IntEnumALERT_DESCRIPTION_ *常量的集合

新版本3.6.

Purpose.SERVER_AUTH
适用于create_default_context()SSLContext.load_default_certs()。此值表示该上下文可用于验证Web服务器(因此,它将用于创建客户端套接字).

版本3.4.

Purpose.CLIENT_AUTH
选项create_default_context()SSLContext.load_default_certs()。此值表示该上下文可用于验证Web客户端(因此,它将用于创建服务器端接字).

版本3.4.

class ssl.SSLErrorNumber
enum.IntEnumSSL_ERROR_ *常量的集合

版本3.6.

class ssl.TLSVersion
enum.IntEnumSSLContext.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.SSLSocketsocket.socket
SSL套接字提供以下方法套接字对象

  • accept()
  • bind()
  • close()
  • connect()
  • detach()
  • fileno()
  • getpeername(), getsockname()
  • getsockopt(), setsockopt()
  • gettimeout(), settimeout(),setblocking()
  • listen()
  • makefile()
  • recv(), recv_into()(但传递非零flags不允许争论)
  • send(), sendall()(同样的限制)
  • sendfile()(但是os.sendfile将仅用于纯文本套接字,否则将使用send()
  • shutdown()

但是,由于SSL(和TLS)协议在TCP上具有自己的成帧,因此SSL套接字抽象在某些方面可能偏离正常的OS级套接字的规范。特别是关于非阻塞插座的说明.

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

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

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

从版本3.6开始不推荐使用:不推荐创建SSLSocket实例直接使用SSLContext.wrap_socket()包好插座

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

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

SSLSocket.readlen=1024, buffer=None
从SSL套接字读取len字节数据,并将结果作为bytes实例返回。如果指定buffer,则读入bufferinstead,并返回读取的字节数.

提起SSLWantReadErrorSSLWantWriteError如果插座是非阻塞并且读取会阻塞

在任何时候都是可以重新协商,调用read()也可以进行写操作.

在版本3.5中更改:每次接收或发送字节时,套接字超时不再复位。套接字超时现在是最大总持续时间,读取到lenbytes.

从版本3.6开始不推荐使用:使用recv()代替read().

SSLSocket.writebuf
buf写入SSLsocket并返回写入的字节数。该buf参数必须是一个支持缓冲接口的对象.

如果插座是SSLWantReadError非阻塞SSLWantWriteError并且写会阻止

在任何时候都可以重新协商,打电话给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:握手期间,OpenSSL匹配主机名或IP地址。功能 match_hostname()不再使用。如果OpenSSL使用主机名或IP地址,则提前中止握手并将TLS警报消息发送给对等方.

SSLSocket.getpeercert (binary_form=False
如果连接另一端的对等体没有证书,则返回None。如果还没有完成SSL握手,请举起ValueError.

如果binary_form参数是False,并且从对等方接收到证书,则此方法返回dict实例如果未验证证书,则该词典为空。如果证书被验证,它将返回一个带有几个键的字典,其中包括subject(颁发证书的委托人)和issuer(颁发证书的校长)。如果证书包含Subject Alternative Name扩展名的实例(参见 RFC 3280 ),字典中也会有一个subjectAltName键.

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', '[email protected]'),)),
 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')),
 'version': 3}

注意

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

如果binary_form参数是True,并提供了证书,此方法返回整个证书的DER编码形式的字节序列,或None如果同伴没有提供证明。对等方是否提供证书取决于SSLsocket的作用:

  • 对于客户端SSL接字,无论是否需要验证,服务器都将始终提供证书;
  • 对于服务器SSL接字,客户端仅在服务器请求时提供证书;因此getpeercert()如果你使用None(而不是CERT_NONECERT_OPTIONAL).CERT_REQUIRED将会返回

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

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

SSLSocket.cipher ()
返回一个三值元组,其中包含正在使用的密码的名称,定义其使用的SSL协议的版本以及正在使用的secretbits的数量。如果没有建立连接,则返回None.
SSLSocket.shared_ciphers
返回握手期间客户端共享的密码列表。返回列表的Eachentry是一个三值元组,包含thecipher的名称,定义其使用的SSL协议的版本,以及密码使用的密码位数。shared_ciphers()返回None如果没有建立连接或套接字是clientocket.

新版本3.5.

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

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

新版本3.3.

SSLSocket.get_channel_binding (cb_type=”tls-unique”)
获取通道绑定当前连接的数据,作为字节对象。返回None如果没有连接或握手没有完成.

cb_type参数允许选择所需的通道绑定类型。有效的通道绑定类型列在CHANNEL_BINDING_TYPES列表中。目前只支持由 RFC 5929 定义的’tls-unique’频道绑定。如果要求不支持的通道绑定类型,ValueError将会被评估.

3.3版本中的新版本.

SSLSocket.selected_alpn_protocol ()
返回在TLS握手期间选择的协议。如果没有调用SSLContext.set_alpn_protocols(),如果对方不支持ALPN,如果此套接字不支持任何客户端提议的协议,或者握手尚未发生,则None返回。

版本3.5中新增.

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

版本3.3.

SSLSocket.unwrap(
执行SSL关闭握手,从而从底层套接字中删除TLS层,并返回底层套接字对象。这可以用于从通过连接的加密操作到未加密的。应始终使用内置插座与连接的另一侧进行进一步通信,而不是原始插座.
SSLSocket.verify_client_post_handshake ()
请求握手后认证(PHA)来自TLS 1.3客户端。在初始TLS握手和双方都启用PHA之后,PHA只能从服务器端套接字启动TLS 1.3连接,请参阅SSLContext.post_handshake_auth.

该方法不立即执行证书交换。服务器端在下一个写入事件期间发送CertificateRequest并期望客户端在下次读取事件时使用证书进行响应.

如果未满足任何前提条件(例如,不是TLS 1.3,未启用PHA),SSLError被抬起

新版本3.7.1.

注意

仅适用于启用OpenSSL 1.1.1和TLS 1.3。如果没有TLS 1.3支持,方法会引发NotImplementedError.

SSLSocket.version
返回连接协商的实际SSL协议版本,或者None是否建立安全连接。在撰写本文时,可能的返回值包括"SSLv2","SSLv3", "TLSv1", "TLSv1.1""TLSv1.2"。新的OpenSSL版本可能会定义更多的返回值.

新版本3.5.

SSLSocket.pending
返回可用于读取的已解密字节数,等待连接.
SSLSocket.context
SSLContext对象此SSL套接字与…有关。如果SSLsocket是使用弃用的wrap_socket()函数(而不是SSLContext.wrap_socket())创建的,则这是为此SSL套接字创建的自定义上下文对象.

新版本3.2.

SSLSocket.server_side
服务器端套接字True的布尔值和False forclient-side sockets.

新版本3.2.

SSLSocket.server_hostname
Hostname of服务器:str类型,或None用于server-sidesocket或者如果在构造函数中没有指定主机名.

新版本3.2.

在版本3.7中更改:该属性现在始终是ASCII文本。当server_hostname是国际化域名(IDN)时,此属性现在存储A标签形式("xn--pythn-mua.org"),而不是U标签形式("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.SSLContextprotocol=PROTOCOL_TLS
创建一个新的SSL上下文。你可以通过protocol,它必须是PROTOCOL_*此模块中定义的常量。参数指定要使用的SSL协议版本。通常,服务器选择特定的协议版本,客户端必须适应服务器的选择。大多数版本不能与其他版本互操作。如果没有指定,默认为PROTOCOL_TLS;它提供与其他版本的最大兼容性.

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

client/ 服务器 SSLv2 SSLv3 TLS [3] TLSv1 TLSv1.1 TLSv1.2
SSLv2 yes no no [1] no no 没有
SSLv3 没有 没有[2] 没有 没有 没有
TLSSSLv23)[3] no [1] no [2]
TLSv1 没有 没有 没有 没有
TLSv1.1 没有 没有 没有 没有
TLSv1.2 没有 没有 没有 没有

脚注

[1] (1, 2) SSLContext默认情况下用OP_NO_SSLv2禁用SSLv2
[2] (1, 2) SSLContext默认情况下用OP_NO_SSLv3禁用SSLv3
[3] (1, 2) //适用于TLS 1.3协议PROTOCOL_TLSinOpenSSL&gt; = 1.1.1。justTLS 1.3没有专用的PROTOCOL常量.

也可以看看

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

版本3.6更改:使用安全默认值创建上下文。选项OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE,OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE,OP_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.

SSLContext.load_cert_chain (certfile, keyfile=None, password=None)
加载私钥和相应的证书。certfilestring必须是包含证书的PEM格式的单个文件的路径,以及建立证书真实性所需的任意数量的CA证书。keyfilestring,如果存在,则必须指向包含私钥的文件。否则私钥也将从certfile中获取。参见证书的讨论有关证书如何存储在certfile.

password参数可以是调用以获取用于加密私钥的密码的函数。只有在加密私钥并且需要密码时才会调用它。它将在没有参数的情况下调用,它应该返回一个字符串,字节或字节数组。如果返回值是字符串,则在使用它来解密密钥之前,它将被编码为UTF-8。或者,可以直接在password论点。如果私钥未加密且无需密码,将被忽略.

如果password如果没有指定参数并且需要密码,OpenSSL的内置密码提示机制将用于交替提示用户输入密码.

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

更改版本3.3:新的可选参数password.

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

purpose flag指定加载哪种CA证书。默认设置Purpose.SERVER_AUTH加载证书,这些证书是TLS Web服务器身份验证(客户端套接字)的标记和信任。Purpose.CLIENT_AUTH服务器端加载CA证书进行客户证书验证.

新版本3.4.

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

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

cafilestring(如果存在)是PEM格式的concatenatedCA证书文件的路径。参见证书的讨论有关如何在此文件中安排证书的更多信息.

capathstring,如果存在,是一个包含几个PEM格式的CA证书的目录的路径,遵循OpenSSL特定的布局.

cadata对象(如果存在)是一个或多个PE编码证书的ASCII字符串,或者是一个字节对象的DER-encodedcertificates。喜欢capathPEM编码的证书周围的额外行被忽略,但必须至少有一个证书.

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

SSLContext.get_ca_certsbinary_form=False
获取已加载的“证书颁发机构”(CA)证书的列表。如果binary_form参数是False每个listentry都是一个像SSLSocket.getpeercert()输出的字典。Otherwisethe方法返回DER编码证书列表。返回的列表不包含来自capath的证书,除非证书是通过SSL连接请求和加载的.

注意

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

新版本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'}]

可用性:OpenSSL 1.0.2 +。

版本3.6.

SSLContext.set_default_verify_paths()
从构建OpenSSL库时定义的文件系统路径加载一组默认的“证书颁发机构”(CA)证书。不幸的是,没有简单的方法可以知道此方法是否成功:如果没有找到证书,则不会返回错误。但是,当OpenSSL库作为操作系统的一部分提供时,它可能会被正确配置.
SSLContext.set_ciphersciphers
设置使用此上下文创建的套接字的可用密码。它应该是OpenSSL密码列表格式的字符串。如果不能选择密码(因为编译时选项或其他配置禁止使用所有指定的密码),SSLError会被提出来

注意

连接时,SSLSocket.cipher()SSL套接字的方法会给当前选择的密码.

OpenSSL 1.1.1默认启用TLS 1.3密码套件。套房不能用set_ciphers().

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

这个方法会提高NotImplementedError如果HAS_ALPNisFalse.

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 / TLShandshake期间应通告的协议。它应该是一个字符串列表,比如["http/1.1", "spdy/2"],按优先顺序排列。协议的选择将在握手期间进行,并将根据应用层协议协商进行。握手成功后,SSLSocket.selected_npn_protocol()方法将返回商定的协议.

这个方法会引发NotImplementedError如果HAS_NPN isFalse.

新版本3.3.

SSLContext.sni_callback
注册一个将在TLS Client Hellohandshake消息后调用的回调函数当TLS客户端指定服务器名称指示时,SSL / TLS服务器已收到此消息。服务器名称指示机制在 RFC 6066中指定第3节 – 服务器名称指示.

每个SSLContext只能设置一个回调。如果sni_callback设置为None则禁用回调。将此函数作为后续时间调用将禁用先前注册的回调.

将使用三个参数调用回调函数;第一个是ssl.SSLSocket,第二个是表示客户端打算通信的服务器名称的字符串(或None,如果TLS客户端Hello不包含服务器名称)和第三个论证是原来的SSLContext。服务器名称参数是文本。对于国际化域名,服务器名称是IDN A标签("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才能继续进行TCP协商。如果需要TLS故障,则可以返回常量ALERT_DESCRIPTION_*。其他返回值将导致TLS致命错误ALERT_DESCRIPTION_INTERNAL_ERROR.

如果从sni_callback函数引发异常,TLSconnection将以致命的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致命的TLSalert消息发送给客户端.

版本3.4中的新功能.

SSLContext.load_dh_params (dhfile)
加载Diffie-Hellman(DH)密钥交换的密钥生成参数。使用DH密钥交换以牺牲计算资源为代价提高了前向保密性(两者都是在服务器和客户端上.dhfile参数应该是包含PEM格式的DH参数的文件的路径.

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

新版本3.3.

SSLContext.set_ecdh_curve (curve_name)
设置基于Elliptic Curve的Diffie-Hellman(ECDH)keyexchange的曲线名称。ECDH明显快于常规DH,但可以说是安全的。curve_name参数应该是一个描述众所周知的椭圆曲线的字符串,例如prime256v1用于广泛支持的曲线.

此设置不适用于客户端套接字。你也可以用OP_SINGLE_ECDH_USE可以选择进一步提高安全性.

如果HAS_ECDHFalse.

这个方法不适用于3.3版本中的新功能

还参见

SSL / TLS&amp;完美向前保密
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插座;OTHERocket类型不受支持.

参数server_side是一个布尔值,用于标识此套接字所需的轮子侧或客户端行为.

对于客户端套接字,上下文构造是懒惰的;如果底层套接字尚未连接,则在connect()在套接字上调用。Forserver端套接字,如果套接字没有远程对等体,则假定它是一个侦听套接字,服务器端SSL包装是在通过accept()方法。该方法可能会引发SSLError.

在客户端连接上,可选参数server_hostname指定我们要连接的服务的主机名。这允许单个服务器使用不同的证书托管多个基于SSL的服务,与HTTP虚拟主机非常相似。指定server_hostnamew 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,请参阅session.

在版本3.5中更改:总是允许传递server_hostname,即使OpenSSL没有SNI.

更改版本3.6:session参数被添加了

更改版本3.7:方法返回SSLContext.sslsocket_class实例而不是硬编码SSLSocket.

SSLContext.sslsocket_class
返回类型SSLContext.wrap_sockets(),默认为SSLSocket。可以在classin实例上覆盖该属性,以返回SSLSocket.

版本3.7.

SSLContext.wrap_bioincoming, outgoing, server_side=False, server_hostname=None, session=None
包裹生物对象incomingoutgoing并返回一个实例ofattr:SSLContext.sslobject_class(默认SSLObject)。SSL例程将从传入的BIO中读取输入数据并将数据写入前面的BIO.

server_side, server_hostnamesession参数与SSLContext.wrap_socket().

版本3.6更改:session争论被添加了

更改版本3.7:该方法返回SSLContext.sslobject_class而不是硬编码SSLObject.

SSLContext.sslobject_class
SSLContext.wrap_bio()的返回类型,默认为SSLObject。可以在classin实例上覆盖该属性,以便在版本3.7.SSLObject.

(

SSLContext.session_stats)中返回
获取有关此上下文创建或管理的SSL会话的统计信息。将返回一个字典,该字典将每条信息的名称映射到其数字值。例如,以下是自创建上下文以来会话高速缓存中的命中和未命中总数:

>>> stats = context.session_stats()
>>> stats['hits'], stats['misses']
(0, 0)
SSLContext.check_hostname
是否将对等证书的主机名与match_hostname()中的SSLSocket.do_handshake()匹配。上下文的verify_mode必须设置为CERT_OPTIONALCERT_REQUIRED,你必须将server_hostname传递给wrap_socket()为了匹配主机名。启用主机名检查自动设置verify_modeCERT_NONECERT_REQUIRED。它不能回到CERT_NONE只要主机名检查已启用.

例:

import socket, ssl

context = ssl.SSLContext()
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.maximum_version
一个 TLSVersion表示最高supportedTLS版本的枚举成员。该值默认为TLSVersion.MAXIMUM_SUPPORTED。该属性对于除PROTOCOL_TLS,PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER.

以外的协议是只读的。属性maximum_version,minimum_versionSSLContext.options所有这些都会影响上下文支持的SSL和TLS版本。该实现不会阻止无效的组合。例如OP_NO_TLSv1_2optionsmaximum_version设置为TLSVersion.TLSv1_2将无法建立TLS 1.2连接.

注意

除非ssl模块是使用OpenSSL 1.1.0g或更新版本编制的,否则此属性不可用

SSLContext.minimum_version
SSLContext.maximum_version除了它是lowestsupported版本或TLSVersion.MINIMUM_SUPPORTED.

注意

除非使用OpenSSL 1.1.0g或更新版本

SSLContext.options
一个整数,表示在此上下文中启用的SSL选项集。默认值OP_ALL,但您可以通过ORing将它们指定为OP_NO_SSLv2等其他选项.

注意

对于早于0.9.8m的OpenSSL版本,只能设置选项,而不是清除它们。试图清除一个选项(通过重置相应的位)会引发一个ValueError.

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

>>> ssl.create_default_context().options  # doctest: +SKIP
<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.

版本3.7.1.

注意

仅适用于启用OpenSSL 1.1.1和TLS 1.3。没有TLS 1.3支持,属性值为None,无法修改

SSLContext.protocol
构造上下文时选择的协议版本。这个属性只读了
SSLContext.hostname_checks_common_name
是的check_hostname在没有主题备用名称扩展名的情况下回退以验证证书的主题通用名称(默认值:true).

版本3.7.

中的新增内容

只能用OpenSSL 1.1.0或更高版本编写.

SSLContext.verify_flags
证书验证操作的标志。你可以设置像VERIFY_CRL_CHECK_LEAF通过ORing他们在一起。默认情况下,OpenSSLdoes既不需要也不验证证书撤销列表(CRL)。只能使用openssl版本0.9.8 +。

版本3.4.

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

>>> ssl.create_default_context().verify_flags  # doctest: +SKIP
<VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
SSLContext.verify_mode
是否尝试验证其他对等方的证书以及如何执行验证失败。该属性必须是CERT_NONE, CERT_OPTIONALCERT_REQUIRED.

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

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

 

 

证书

证书通常是公钥/私钥系统的一部分。在这个系统中,每个校长,(可以是机器,或人,或组织)被分配一个唯一的两部分加密密钥。keyis public的一部分,被称为公钥;另一部分是保密的,被称为私钥。这两部分是相关的,因为如果用其中一个部分加密一条消息,你可以用另一部分解密它,而只用另一部分来解密.

证书包含有关两个主体的信息。它包含主题的名称和主题的公钥。它还包含第二个委托人发行人的声明,该主题是他们声称的主题,并且这确实是主题的公钥。发行人的声明是与发行人的私钥签订的,只有发行人知道。但是,任何人都可以通过查找发行者的公钥,解密发布者的声明,并将其与证书中的其他信息进行比较来验证发行人的声明。证书还包含有关其无效的时间段的信息。这表示为两个字段,称为“notBefore”和“notAfter”.

在Python使用证书时,客户端或服务器可以使用证书toprove。还可以要求网络连接的另一侧产生证书,并且该证书可以被验证以满足需要这种验证的客户端或服务器的需求。如果验证失败,则可以将连接尝试设置为引发异常。验证由底层OpenSSL框架自动完成;应用程序不需要关注其机制。但是应用程序通常需要提供一组证书来允许这个过程进行.

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

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

证书链

包含证书的Python文件可以包含一系列证书,有时称为证书链。该链应该以“是”客户或服务器的委托人的特定证书开头,然后是该证书的发行人的证书,然后是的发行人的证明证书,等链上tillyou得到证书自签名,即证书有相同的主题和发行人,有时称为根证书。证书应该只在证书文件中连接在一起。例如,假设我们有三个证书链,从我们的服务器证书到签署我们的服务器证书的证书颁发机构的证书,到颁发证书颁发机构证书的机构的根证书:

-----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 []:[email protected]
%

自签名证书的缺点是它是自己的rootcertificate,没有其他人会在它们的缓存中使用它已知(和可信)的根证书.

示例

测试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()
>>> context.verify_mode = ssl.CERT_REQUIRED
>>> context.check_hostname = True
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(这个片段假设您的操作系统在/etc/ssl/certs/ca-bundle.crt中放置了一捆所有CAcertificates;如果没有,您将得到一个错误并且必须调整位置)

当您使用上下文连接到服务器时,CERT_REQUIRED验证服务器证书:它确保服务器证书使用其中一个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

然后回去听新的客户端连接(当然,一个真正的服务器可能会在一个单独的线程中处理每个客户端连接,或者将套接字置于非阻塞模式并使用事件循环).

 

关于非阻塞套接字的注释

SSL接字与常规套接字无阻塞模式略有不同。使用非阻塞套接字时,您需要注意以下几点:

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

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

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

  • 相反,由于SSL层有自己的框架,SSL套接字maystill有数据可供阅读而没有select()意识到它的。因此,你应该先调用SSLSocket.recv()来排空任何可能存在的数据,然后如果仍然必要的话,只能阻止select()通话.

    (当然,类似的规定适用于使用其他原语如poll(),或selectors模块中的那些

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

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

另见

asyncio模块支持非阻塞SSL接字并提供更高级别的API。它使用selectors模块和句柄SSLWantWriteError, SSLWantReadErrorBlockingIOError异常轮询事件。它也异步运行SSL握手.

内存生成器支持

版本3.5中的新功能

自从SSL 2.6中引入SSL模块以来,SSLSocket class提供了两个相关但不同的功能区域:

  • 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的框架作者使用.

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

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

可以使用以下方法:

  • context
  • server_side
  • server_hostname
  • session
  • session_reused
  • read()
  • write()
  • getpeercert()
  • selected_npn_protocol()
  • cipher()
  • shared_ciphers()
  • compression()
  • pending()
  • do_handshake()
  • unwrap()
  • get_channel_binding()

相比 SSLSocket,这个对象缺少以下特征:

  • 任何形式的网络IO;recv()send()只读到底层MemoryBIO缓冲区
  • 没有do_handshake_on_connect机械。你必须总是手动调用do_handshake()开始握手.
  • 没有处理suppress_ragged_eofs。通过SSLEOFErrorexception
  • 方法unwrap() call不会返回任何内容,不像SSL套接字返回底层套接字.
  • server_name_callback回调传递给SSLContext.set_servername_callback()会得到SSLObject实例而不是SSLSocket实例作为其第一个参数.

有些注意事项与SSLObject

  • 所有IO都在SSLObject非阻塞这意味着,例如read()如果它需要的数据多于传入的BIO可用数据SSLWantReadError将会增加
  • 没有模块级wrap_bio()就像wrap_socket()那样调用。SSLObject总是通过SSLContext.

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

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

class ssl.MemoryBIO
一个内存缓冲区,可用于在Python和SSL协议实例之间传递数据.

pending
返回内存缓冲区中当前的字节数.
eof
一个布尔值,指示内存BIO是否在end-of-文件位置是最新的
readn=-1
阅读n来自内存缓冲区的字节。如果n如果没有指定或者为负,则返回所有字节.
write (buf)
buf中的字节写入内存BIO。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证书,启用证书验证和主机名检查,并尝试选择合理的secureprotocol和密码设置.

例如,以下是如何使用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_hostnameisenabled.

更改版本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开始,默认情况下,thessl模块禁用某些弱密码,但您可能希望进一步限制密码选择。请务必阅读OpenSSL关于密码列表格式的文档。如果要检查给定密码列表启用了哪些密码,请在yoursystem上使用SSLContext.get_ciphers()openssl ciphers命令.

多处理

如果将此模块用作多处理应用程序的一部分(例如使用multiprocessingconcurrent.futures模块),请注意OpenSSL的内部随机数字生成器不能正确处理分叉进程。如果应用程序使用任何带有os.fork()的SSL功能,应用程序必须更改该进程的PRNG状态。RAND_add(), RAND_bytes()RAND_pseudo_bytes()的成功调用就足够了

 

TLS 1.3

版本3.7.

Python有临时和实验支持对于带有OpenSSL1.1.1的TLS 1.3。新协议的行为与先前版本的TLS / SSL略有不同。一些新的TLS 1.3功能尚不可用.

  • TLS 1.3使用一组分离的密码套件。默认情况下,所有AES-GCM和ChaCha20密码套件均已启用。方法SSLContext.set_ciphers()还不能启用或禁用任何TLS 1.3ciphers,但SSLContext.get_ciphers()返回它们
  • 会话票证不再作为初始握手的一部分发送,并且处理方式不同。SSLSocket.sessionSSLSession与TLS 1.3不兼容.
  • 初始握手期间也不再验证客户端证书。服务器可以随时请求证书。客户端在从服务器发送或接收应用程序数据时处理证书请求.
  • TLS 1.3的功能如早期数据,延迟TLS客户端证书请求,签名算法配置和重新加密都不支持.

 

LibreSSL支持

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

  • LibreSSL&gt; = 2.6.1不再支持NPN。方法SSLContext.set_npn_protocols()SSLSocket.selected_npn_protocol()没有.
  • SSLContext.set_default_verify_paths()忽略了env vars SSL_CERT_FILESSL_CERT_PATH虽然get_default_verify_paths()还在报告它们

参见

socket.socket
基础socket类的文档
SSL / TLS强加密:简介
来自Apache HTTP Server文档的介绍
RFC 1422:Internet电子邮件的隐私增强:第二部分:基于证书的密钥管理
Steve Kent
RFC 4086:安全随机性要求
Donald E.,Jeffrey I. Schiller
RFC 5280:Internet X.509公钥基础结构证书和证书撤销列表(CRL)配置文件
D.Cooper
RFC 5246:传输层安全性(TLS)协议版本1.2
T.Dierks等。al.
RFC 6066:传输层安全性(TLS)扩展
D.Eastlake
IANA TLS:传输层安全性(TLS)参数
IANA
RFC 7525:安全使用传输层安全性(TLS)和数据报传输层安全性的建议(DTLS)
IETF
Mozilla的服务器端TLS建议
Mozilla