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

目录

  • ssl - 套接字对象的TLS / SSL包装器
    • 函数,常量和异常
      • 套接字创建
      • 上下文创建
      • 例外
      • 随机生成
      • 证书处理
      • 常量
    • SSL套接字
    • SSL上下文
    • 证书
      • 证书链
      • CA证书
      • 组合密钥和证书
      • 自签名证书
    • 例子
      • 测试SSL支持
      • 客户端操作
      • 服务器端操作
    • 关于非阻塞套接字的注意事项
    • 内存生物支持
    • SSL会话
    • 安全考虑
      • 最佳默认值
      • 手动设置
        • 验证证书
        • 协议版本
        • 密码选择
      • 多处理
    • TLS 1.3
    • LibreSSL支持

源代码: Lib / ssl.py


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

注意

 

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

警告

 

如果不阅读安全注意事项,请勿使用此模块。这样做可能会导致错误的安全感,因为ssl模块的默认设置不一定适合您的应用程序。

本节介绍了ssl模块中的对象和功能; 有关TLS,SSL和证书的更多常规信息,读者可参阅底部“另请参阅”部分中的文档。

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

对于更复杂的应用程序,ssl.SSLContext该类有助于管理设置和证书,然后可以通过该SSLContext.wrap_socket()方法创建的SSL套接字继承这些设置和证书。

版本3.5.3中已更改:已更新以支持与OpenSSL 1.1.0的链接

版本3.6中已更改:不推荐使用OpenSSL 0.9.8,1.0.0和1.0.1,不再支持。将来,ssl模块至少需要OpenSSL 1.0.2或1.1.0。

函数,常量和异常

套接字创建

因为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.SERVER_AUTHcafile = Nonecapath = Nonecadata = None 

SSLContext为给定目的返回具有默认设置的新对象。这些设置由ssl模块选择,并且通常表示比SSLContext直接调用构造函数时更高的安全级别 。

cafilecapathcadata表示可信任证书验证的可选CA证书,如 SSLContext.load_verify_locations()。如果全部三个 None,则此功能可以选择信任系统的默认CA证书。

设置为:PROTOCOL_TLSOP_NO_SSLv2和 OP_NO_SSLv3高加密密码套件,没有RC4,没有未经验证的密码套件。传递SERVER_AUTH 为目的设置verify_modeCERT_REQUIRED 与任一负载CA证书(当中的至少一个凭证档案错误capath或 cadata给出),或者使用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已从默认密码字符串中删除。

例外

异常ssl.SSLError

引发信号从基础SSL实现(当前由OpenSSL库提供)发出错误。这表示在基础网络连接上叠加的更高级别加密和身份验证层存在一些问题。此错误是的子类型OSErrorSSLError实例的错误代码和消息 由OpenSSL库提供。

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

library

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

版本3.3中的新功能。

reason

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

版本3.3中的新功能。

异常ssl.SSLZeroReturnError

SSLError尝试读取或写入时引发的子类以及SSL连接已完全关闭。请注意,这并不意味着底层传输(读取TCP)已关闭。

版本3.3中的新功能。

异常ssl.SSLWantReadError

尝试读取或写入数据时SSLError由非阻塞SSL套接字引发的子类,但在满足请求之前,需要在底层TCP传输上接收更多数据。

版本3.3中的新功能。

异常ssl.SSLWantWriteError

尝试读取或写入数据时SSLError由非阻塞SSL套接字引发的子类,但在满足请求之前需要在底层TCP传输上发送更多数据。

版本3.3中的新功能。

异常ssl.SSLSyscallError

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

版本3.3中的新功能。

异常ssl.SSLEOFError

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

版本3.3中的新功能。

异常ssl.SSLCertVerificationError

SSLError证书验证失败时引发的子类。

版本3.7中的新功能。

verify_code

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

verify_message

人类可读的验证错误字符串。

异常ssl.CertificateError

别名SSLCertVerificationError

版本3.7中已更改:异常现在是别名SSLCertVerificationError

随机生成

ssl.RAND_bytesnum 

返回num加密强伪随机字节。SSLError如果PRNG没有播种足够的数据或者当前RAND方法不支持该操作,则引发一个 。RAND_status() 可用于检查PRNG的状态,RAND_add()并可用于播种PRNG。

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

阅读维基百科文章,加密安全伪随机数生成器(CSPRNG),以获得加密生成器的要求。

版本3.3中的新功能。

ssl.RAND_pseudo_bytesnum 

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

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

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

版本3.3中的新功能。

从版本3.6开始不推荐ssl.RAND_pseudo_bytes()使用 OpenSSL已弃用,请 ssl.RAND_bytes()改用。

ssl.RAND_status()

返回True如果SSL伪随机数生成器已经播种了“足够的”随机性,以及False其他。您可以使用 ssl.RAND_egd()ssl.RAND_add()增加伪随机数生成器的随机性。

ssl.RAND_egd路径

如果你正在某处运行一个熵收集守护进程(EGD),并且path 是打开它的套接字连接的路径名,这将从套接字中读取256字节的随机性,并将其添加到SSL伪随机数生成器中增加生成的密钥的安全性。这通常仅在没有更好随机源的系统上是必需的。

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

可用性:不适用于LibreSSL和OpenSSL> 1.1.0。

ssl.RAND_add字节

将给定的字节混合到SSL伪随机数生成器中。参数entropy(浮点数)是字符串中包含的熵的下限(因此您可以随时使用0.0)。看到有关熵源的更多信息,请参阅 RFC 1750

在版本3.5中更改:现在接受可写的字节对象。

证书处理

ssl.match_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 "", line 1, in 
  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),也不匹配通配符。IDN A标签www*.xn--pthon-kva.org仍然受支持,但x*.python.org不再匹配xn--tda.python.org

版本3.5中已更改:现在支持匹配IP地址(当存在于证书的subjectAltName字段中时)。

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

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

自3.7版以来已弃用。

ssl.cert_time_to_secondscert_time 

返回自Epoch以来的秒数,给定cert_time 字符串代表strptime格式(C语言环境)证书的“notBefore”或“notAfter”日期。"%b %d %H:%M:%S %Y %Z"

这是一个例子:

>>> 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”时区指定。之前使用过本地时区。返回一个整数(输入格式中没有一秒的分数)

ssl.get_server_certificateaddrssl_version = PROTOCOL_TLSca_certs = None 

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

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

改变在3.5版本:默认SSL_VERSION从改变PROTOCOL_SSLv3到 PROTOCOL_TLS与现代服务器的最大兼容性。

ssl.DER_cert_to_PEM_certDER_cert_bytes 

将证书作为DER编码的字节blob,返回相同证书的PEM编码字符串版本。

ssl.PEM_cert_to_DER_certPEM_cert_string 

将证书作为ASCII PEM字符串,返回相同证书的DER编码字节序列。

ssl.get_default_verify_paths()

返回一个带有OpenSSL默认cafile和capath路径的命名元组。路径与使用的路径相同SSLContext.set_default_verify_paths()。返回值是一个 命名元组 DefaultVerifyPaths

  • cafile- 解决了cafile的路径或者None文件不存在,
  • capath- 已解决的capath路径或None目录不存在,
  • openssl_cafile_env - OpenSSL的环境键,指向一个咖啡馆,
  • openssl_cafile - 到咖啡馆的硬编码路径,
  • openssl_capath_env - OpenSSL的环境密钥指向一个capath,
  • openssl_capath - capath目录的硬编码路径

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

版本3.4中的新功能。

ssl.enum_certificatesstore_name 

从Windows的系统证书库中检索证书。store_name可以是CAROOT或者之一MY。Windows也可能提供额外的证书存储。

该函数返回(cert_bytes,encoding_type,trust)元组的列表。encoding_type指定cert_bytes的编码。它x509_asn适用于X.509 ASN.1数据或pkcs_7_asnPKCS#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_crlsstore_name 

从Windows的系统证书存储中检索CRL。store_name可以是CAROOT或者之一MY。Windows也可能提供额外的证书存储。

该函数返回(cert_bytes,encoding_type,trust)元组的列表。encoding_type指定cert_bytes的编码。它x509_asn适用于X.509 ASN.1数据或pkcs_7_asnPKCS#7 ASN.1数据。

可用性:Windows。

版本3.4中的新功能。

ssl.wrap_socketsockkeyfile = Nonecertfile = Noneserver_side = Falsecert_reqs = CERT_NONEssl_version = PROTOCOL_TLSca_certs = Nonedo_handshake_on_connect = Truesuppress_ragged_eofs = Trueciphers = None 

需要一个实例socksocket.socket,并且返回的一个实例ssl.SSLSocket,的一个亚型socket.socket,它包装在SSL上下文底层套接字。 sock必须是一个 SOCK_STREAM插座; 其他套接字类型不受支持。

在内部,函数SSLContext使用协议 ssl_version创建一个并SSLContext.options设置为cert_reqs。如果参数的密钥文件certFile中ca_certs密码被设置,则该值被传递到SSLContext.load_cert_chain()SSLContext.load_verify_locations(),和 SSLContext.set_ciphers()

参数server_sidedo_handshake_on_connect和 suppress_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 如果验证失败,如果没有提供证书将提高,或。这种模式是足够的客户端模式验证证书,因为它不匹配的主机名。 check_hostname必须启用以验证证书的真实性。 默认PROTOCOL_TLS_CLIENT使用CERT_REQUIRED和启用check_hostname

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

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

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证书。该模式需要由对等证书颁发者(其直接祖先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。它指示OpenSSL在构建信任链以验证证书时更喜欢可信证书。默认情况下启用此标志。

版本3.4.4中的新功能。

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

数据别名:PROTOCOL_TLS。

从版本3.6开始不推荐使用:PROTOCOL_TLS改为使用。

ssl.PROTOCOL_SSLv2

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

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

警告

 

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

从版本3.6开始不推荐使用: OpenSSL已删除对SSLv2的支持。

ssl.PROTOCOL_SSLv3

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

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

警告

 

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

从版本3.6开始不推荐使用 OpenSSL已弃用所有特定于版本的协议。请使用PROTOCOL_TLS带有标志的默认协议OP_NO_SSLv3

ssl.PROTOCOL_TLSv1

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

从版本3.6开始不推荐使用 OpenSSL已弃用所有特定于版本的协议。请使用PROTOCOL_TLS带有标志的默认协议OP_NO_SSLv3

ssl.PROTOCOL_TLSv1_1

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

版本3.4中的新功能。

从版本3.6开始不推荐使用 OpenSSL已弃用所有特定于版本的协议。请使用PROTOCOL_TLS带有标志的默认协议OP_NO_SSLv3

ssl.PROTOCOL_TLSv1_2

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

版本3.4中的新功能。

从版本3.6开始不推荐使用 OpenSSL已弃用所有特定于版本的协议。请使用PROTOCOL_TLS带有标志的默认协议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作为协议版本。OpenSSL 1.1.1或更高版本提供TLS 1.3。当Python针对旧版本的OpenSSL进行编译时,标志默认为0

版本3.7中的新功能。

从版本3.7开始不推荐使用:自OpenSSL 1.1.0以来,该选项已弃用。为了向后兼容OpenSSL 1.0.2,它被添加到2.7.15,3.6.3和3.7.0。

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中的新功能。

ssl.Options

enum.IntFlag OP_ *常量的集合。

ssl.OP_NO_TICKET

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

版本3.6中的新功能。

ssl.HAS_ALPN

OpenSSL库是否内置了对应用层协议协商 TLS扩展的支持,如中所述RFC 7301

版本3.5中的新功能。

ssl.HAS_NEVER_CHECK_COMMON_NAME

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

版本3.7中的新功能。

ssl.HAS_ECDH

OpenSSL库是否内置支持基于Elliptic Curve的Diffie-Hellman密钥交换。除非分发者明确禁用该功能,否则这应该是真的。

版本3.3中的新功能。

ssl.HAS_SNI

OpenSSL库是否内置支持Server Name Indication扩展(如中所定义)RFC 6066)。

版本3.2中的新功能。

ssl.HAS_NPN

OpenSSL库是否内置了对应用层协议协商中描述的下一协议协商的支持。如果为true,则可以使用该方法来宣传要支持的协议。SSLContext.set_npn_protocols()

版本3.3中的新功能。

ssl.HAS_SSLv2

OpenSSL库是否内置了对SSL 2.0协议的支持。

版本3.7中的新功能。

ssl.HAS_SSLv3

OpenSSL库是否内置了对SSL 3.0协议的支持。

版本3.7中的新功能。

ssl.HAS_TLSv1

OpenSSL库是否内置了对TLS 1.0协议的支持。

版本3.7中的新功能。

ssl.HAS_TLSv1_1

OpenSSL库是否内置了对TLS 1.1协议的支持。

版本3.7中的新功能。

ssl.HAS_TLSv1_2

OpenSSL库是否内置了对TLS 1.2协议的支持。

版本3.7中的新功能。

ssl.HAS_TLSv1_3

OpenSSL库是否内置了对TLS 1.3协议的支持。

版本3.7中的新功能。

ssl.CHANNEL_BINDING_TYPES

支持的TLS通道绑定类型列表。此列表中的字符串可用作参数SSLSocket.get_channel_binding()

版本3.3中的新功能。

ssl.OPENSSL_VERSION

解释器加载的OpenSSL库的版本字符串:

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

版本3.2中的新功能。

ssl.OPENSSL_VERSION_INFO

一个包含五个整数的元组,表示有关OpenSSL库的版本信息:

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

版本3.2中的新功能。

ssl.OPENSSL_VERSION_NUMBER

OpenSSL库的原始版本号,作为单个整数:

>>>
>>> ssl.OPENSSL_VERSION_NUMBER
268443839
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
'0x100020bf'

版本3.2中的新功能。

ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE

ssl.ALERT_DESCRIPTION_INTERNAL_ERROR

ALERT_DESCRIPTION_*

来自的警报描述 RFC 5246等。该 IANA TLS警报注册表 包含此列表,并引用到自己的意思被定义RFC文档。

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

版本3.4中的新功能。

ssl.AlertDescription

enum.IntEnum ALERT_DESCRIPTION_ *常量的集合。

版本3.6中的新功能。

Purpose.SERVER_AUTH

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

版本3.4中的新功能。

Purpose.CLIENT_AUTH

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

版本3.4中的新功能。

ssl.SSLErrorNumber

enum.IntEnum SSL_ERROR_ *常量的集合。

版本3.6中的新功能。

ssl.TLSVersion

enum.IntEnum用于SSLContext.maximum_version和的SSL和TLS版本的集合 SSLContext.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套接字提供以下Socket对象方法:

  • 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()不会每个字节接收或发送时间重置套接字超时。套接字超时现在是关闭的最大总持续时间。

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

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

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

SSLSocket.readlen = 1024缓冲区=无

从SSL套接字读取len个字节的数据,并将结果作为bytes实例返回。如果缓冲器被指定,然后读入到缓冲液代替,并返回读出的字节数。

提升SSLWantReadError或者SSLWantWriteError如果套接字是 非阻塞的,则读取将阻塞。

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

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

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

SSLSocket.writebuf 

buf写入SSL套接字并返回写入的字节数。所述 的buf参数必须是支撑所述缓冲器接口的对象。

提升SSLWantReadError或者SSLWantWriteError如果套接字是 非阻塞的,则写入将阻塞。

在任何时候都可以进行重新协商,调用write()也可以导致读操作。

在版本3.5中更改:每次接收或发送字节时,套接字超时不再复位。套接字超时现在是写入buf的最大总持续时间。

从版本3.6开始不推荐使用:send()代替使用write()

注意

 

read()write()方法是读取和写入未加密的,应用级数据和解密/加密它以加密的,电线级数据的低级别的方法。这些方法需要主动SSL连接,即握手已完成 SSLSocket.unwrap()且未被调用。

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

SSLSocket.do_handshake()

执行SSL设置握手。

改变在3.4版本:握手方法还执行match_hostname()当 check_hostname套接字的属性 context为true。

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

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

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

注意

 

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

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

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

在版本3.2中更改:返回的字典包括其他项目,如issuer 和notBefore

更改版本3.4:ValueError在未完成握手时引发。返回的字典包括额外采用X509v3扩展项目,如crlDistributionPointscaIssuersOCSP的URI。

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_bindingcb_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之后,PHA只能从服务器端套接字启动TLS 1.3连接,请参阅 SSLContext.post_handshake_auth

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

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

注意

 

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

3.7.1版中的新功能。

SSLSocket.version()

将连接协商的实际SSL协议版本作为字符串返回,或者None没有建立安全连接。在撰写本文时,可能的返回值包括"SSLv2", "SSLv3""TLSv1""TLSv1.1""TLSv1.2"。最近的OpenSSL版本可能会定义更多的返回值。

版本3.5中的新功能。

SSLSocket.pending()

返回连接上可读取,待处理的已解密字节数。

SSLSocket.context

SSLContext此SSL套接字绑定的对象。如果SSL套接字是使用不推荐使用的wrap_socket()函数(而不是SSLContext.wrap_socket())创建的,则这是为此SSL套接字创建的自定义上下文对象。

版本3.2中的新功能。

SSLSocket.server_side

一个布尔值,True用于服务器端套接字和False客户端套接字。

版本3.2中的新功能。

SSLSocket.server_hostname

服务器的主机名:str类型,或None服务器端套接字,或者在构造函数中未指定主机名。

版本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_*此模块中定义的常量之一。该参数指定要使用的SSL协议版本。通常,服务器选择特定的协议版本,客户端必须适应服务器的选择。大多数版本不能与其他版本互操作。如果未指定,则默认为 PROTOCOL_TLS; 它提供与其他版本最兼容。

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

客户 / 服务器 的SSLv2 在SSLv3 TLS [3] 使用TLSv1 TLSv1.1 TLSv1.2工作
的SSLv2 没有 没有[1] 没有 没有 没有
在SSLv3 没有 没有[2] 没有 没有 没有
TLSSSLv23)[3] 没有[1] 没有[2]
使用TLSv1 没有 没有 没有 没有
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_TLSOpenSSL中> = 1.1.1。仅TLS 1.3没有专用的PROTOCOL常量。

也可以看看

 

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

版本3.6中已更改:使用安全默认值创建上下文。选项 OP_NO_COMPRESSIONOP_CIPHER_SERVER_PREFERENCEOP_SINGLE_DH_USEOP_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_chaincertfilekeyfile = Nonepassword = None 

加载私钥和相应的证书。所述certFile中 字符串必须的路径PEM格式包含证书以及任何号码,以建立证书的真实性所需要的CA证书的单个文件。该密钥文件的字符串,如果存在的话,必须指向包含私有密钥的文件,否则私钥将采取certFile中也是如此。有关证书如何存储在certfile中的更多信息,请参阅证书的讨论 。

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

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

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

在版本3.3中更改:新的可选参数密码

SSLContext.load_default_certs目的= Purpose.SERVER_AUTH 

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

目的标志指定类型的CA证书加载什么。默认设置Purpose.SERVER_AUTH加载了TLS Web服务器身份验证(客户端套接字)标记和信任的证书。Purpose.CLIENT_AUTH在服务器端加载CA证书以进行客户端证书验证。

版本3.4中的新功能。

SSLContext.load_verify_locationscafile = Nonecapath = Nonecadata = None 

加载一组“认证权威”一起使用时,以验证其他对等端的证书(CA)证书的verify_mode比其他 CERT_NONE。必须指定至少一个cafilecapath

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

凭证档案错误串,如果存在的话,是路径到PEM格式级联CA证书的文件。有关如何在此文件中排列证书的详细信息,请参阅证书的讨论 。

capath串,如果存在的话,是路径到包含PEM格式几个CA证书,以下内容的一个目录的OpenSSL特定布局。

cadata对象,如果存在的话,或者是一个或多个PEM编码证书的ASCII字符串或类字节对象 DER编码的证书。与capath一样,PEM编码证书周围的额外行被忽略,但必须至少存在一个证书。

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

SSLContext.get_ca_certsbinary_form = False 

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

注意

 

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

版本3.4中的新功能。

SSLContext.get_ciphers()

获取已启用密码的列表。该列表按密码优先级顺序排列。见SSLContext.set_ciphers()

例:

>>>
>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
>>> ctx.get_ciphers()  # 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_ciphers密码

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

注意

 

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

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

SSLContext.set_alpn_protocols协议

指定套接字在SSL / TLS握手期间应通告的协议。它应该是一个ASCII字符串列表,例如,按优先顺序排序。协议的选择将在握手期间发生,并将根据情况发挥作用['http/1.1', 'spdy/2']RFC 7301。成功握手后,该SSLSocket.selected_alpn_protocol()方法将返回商定的协议。

NotImplementedError如果HAS_ALPN为False,则此方法将引发。

SSLError 当双方都支持ALPN但无法就协议达成一致时,OpenSSL 1.1.0到1.1.0e将中止握手并提升。1.1.0f +表现得像1.0.2,SSLSocket.selected_alpn_protocol()返回None。

版本3.5中的新功能。

SSLContext.set_npn_protocols协议

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

NotImplementedError如果HAS_NPN为False,则此方法将引发。

版本3.3中的新功能。

SSLContext.sni_callback

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

每个只能设置一个回调SSLContext。如果 设置了sni_callbackNone则禁用回调。随后调用此函数将禁用先前注册的回调。

回调函数将使用三个参数调用; 第一个是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客户端问候,并因此将不包含返回有意义的值,也不能被安全地调用。

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

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

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

版本3.7中的新功能。

SSLContext.set_servername_callbackserver_name_callback 

这是为保持向后兼容性而保留的遗留API。如果可能,您应该使用sni_callback。给定的server_name_callback 类似于sni_callback,除了当服务器主机名是IDN编码的国际化域名时,server_name_callback 接收解码的U-label("pythön.org")。

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

版本3.4中的新功能。

SSLContext.load_dh_paramsdhfile 

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

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

版本3.3中的新功能。

SSLContext.set_ecdh_curvecurve_name 

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

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

如果HAS_ECDH是,则此方法不可用False

版本3.3中的新功能。

也可以看看

SSL / TLS和完美的前向保密

文森特伯纳特。

SSLContext.wrap_socketsockserver_side = Falsedo_handshake_on_connect = Truesuppress_ragged_eofs = Trueserver_hostname = Nonesession = None 

包装现有的Python套接字sock并返回SSLContext.sslsocket_class(默认SSLSocket)实例 。返回的SSL套接字与上下文,其设置和证书相关联。 袜子必须是SOCK_STREAM插座; 其他套接字类型不受支持。

该参数server_side是一个布尔值,用于标识此套接字是否需要服务器端或客户端行为。

对于客户端套接字,上下文构造是懒惰的; 如果底层套接字尚未连接,则connect()在套接字上调用后将执行上下文构造。对于服务器端套接字,如果套接字没有远程对等体,则假定它是侦听套接字,并且在通过该accept()方法接受的客户端连接上自动执行服务器端SSL包装 。该方法可能会提高SSLError

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

该参数do_handshake_on_connect指定在执行a后socket.connect()是否自动执行SSL握手,或者应用程序是否将通过调用SSLSocket.do_handshake()方法显式调用它 。SSLSocket.do_handshake()显式调用 使程序可以控制握手中涉及的套接字I / O的阻塞行为。

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

会议,见session

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

在版本3.6中更改:添加了会话参数。

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

SSLContext.sslsocket_class

返回类型SSLContext.wrap_sockets(),默认为 SSLSocket。可以在类的实例上覆盖该属性,以便返回自定义子类SSLSocket

版本3.7中的新功能。

SSLContext.wrap_bio传入传出server_side = Falseserver_hostname =无session =无

包装传入传出的BIO对象并返回attr的实例: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会话的统计信息。返回一个字典,它将每条信息的名称映射到它们的数值。例如,以下是自创建上下文以来会话缓存中的命中和未命中总数:

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

SSLContext.check_hostname

是否将对等证书的主机名与match_hostname()in 匹配SSLSocket.do_handshake()。上下文的 verify_mode必须设置为CERT_OPTIONAL或 CERT_REQUIRED,你必须通过server_hostname到 wrap_socket()为了匹配的主机名。启用主机自动检测设置verify_mode,从 CERT_NONECERT_REQUIREDCERT_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表示支持的最高TLS版本枚举成员。该值默认为TLSVersion.MAXIMUM_SUPPORTED。对于除PROTOCOL_TLSPROTOCOL_TLS_CLIENT,和之外的协议, 该属性是只读的PROTOCOL_TLS_SERVER

属性maximum_version, minimum_version并且 SSLContext.options所有影响环境的支持SSL和TLS版本。实现不会阻止无效组合。例如,具有OP_NO_TLSv1_2in options和 maximum_versionset 的上下文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.options

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

注意

 

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

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

>>> ssl.create_default_context().options  # doctest: +SKIP

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支持,则属性值为None且无法修改

3.7.1版中的新功能。

SSLContext.protocol

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

SSLContext.hostname_checks_common_name

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

注意

 

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

版本3.7中的新功能。

SSLContext.verify_flags

证书验证操作的标志。您可以VERIFY_CRL_CHECK_LEAF通过将它们组合在一起来设置标记 。默认情况下,OpenSSL既不需要也不验证证书吊销列表(CRL)。仅适用于openssl 0.9.8+版本。

版本3.4中的新功能。

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

>>> ssl.create_default_context().verify_flags  # doctest: +SKIP

SSLContext.verify_mode

是否尝试验证其他对等方的证书以及验证失败时的行为方式。该属性必须是一个 CERT_NONECERT_OPTIONALCERT_REQUIRED

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

>>> ssl.create_default_context().verify_mode

证书

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

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

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

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

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

证书链

包含证书的Python文件可以包含一系列证书,有时称为证书链。这个链应该与校长谁“是”客户端或服务器,然后该证书的颁发的证书,然后对发行人的证书的特定证书启动证书,依此类推,直到链,直到你获取自签名的证书,即具有相同主题和颁发者的证书,有时称为根证书。证书应该只在证书文件中连接在一起。例如,假设我们有三个证书链,从我们的服务器证书到签署我们的服务器证书的证书颁发机构的证书,到颁发证书颁发机构证书的机构的根证书:

-----BEGIN CERTIFICATE-----
... (certificate for your server)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the certificate for the CA)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the root certificate for the CA's issuer)...
-----END CERTIFICATE-----

CA证书

如果您要求验证连接证书的另一端,则需要提供“CA证书”文件,其中包含您愿意信任的每个颁发者的证书链。同样,这个文件只包含连接在一起的这些链。为了验证,Python将使用它在匹配的文件中找到的第一个链。平台的证书文件可以通过调用来使用SSLContext.load_default_certs(),这是自动完成的create_default_context()

组合密钥和证书

私钥通常与证书存储在同一文件中; 在这种情况下,只有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()
>>> context.verify_mode = ssl.CERT_REQUIRED
>>> context.check_hostname = True
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(此代码段假设您的操作系统放置了一捆所有CA证书/etc/ssl/certs/ca-bundle.crt;如果没有,您将收到错误并且必须调整位置)

使用上下文连接到服务器时,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套接字的行为与常规套接字略有不同。使用非阻塞套接字时,您需要注意以下几点:

  • 如果I / O操作会阻塞,大多数SSLSocket方法都会引发 SSLWantWriteErrorSSLWantReadError代替BlockingIOErrorSSLWantReadError如果需要对底层套接字执行读操作,并且SSLWantWriteError对底层套接字执行写操作,则会引发此操作。需要注意的是试图 至SSL套接字可能需要读取从底层插座中,并试图读取从SSL套接字可能要求之前写入到底层插座。

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

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

  • 相反,由于SSL层具有自己的框架,因此SSL套接字可能仍然具有可用于读取的数据而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模块和把手SSLWantWriteErrorSSLWantReadError和 BlockingIOError例外。它也异步运行SSL握手。

内存生成器支持

版本3.5中的新功能。

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

  • SSL协议处理
  • 网络IO

网络IO API与提供的网络IO API相同socket.socketSSLSocket也从中继承。这允许将SSL套接字用作常规套接字的替代品,从而可以非常轻松地向现有应用程序添加SSL支持。

将SSL协议处理和网络IO结合起来通常效果很好,但在某些情况下却没有。一个示例是异步IO框架,它们希望使用与“文件描述符上的选择/轮询”(基于准备就绪)模型不同的IO多路复用模型,该模型socket.socket 由内部OpenSSL套接字IO例程假设。这主要与Windows等平台无关,这种模式效率不高。为此目的,提供了一种缩小范围的SSLSocket被调用变体SSLObject

ssl.SSLObject

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

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

这个类没有公共构造函数。一个SSLObject实例必须使用创建wrap_bio()方法。此方法将创建SSLObject实例并将其绑定到一对BIO。该传入 BIO用于从Python的数据传递到所述SSL协议实例,而传出 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。通过SSLEOFError异常报告所有违反协议的文件结束条件 。
  • 方法unwrap()调用不会返回任何内容,这与它返回底层套接字的SSL套接字不同。
  • 传递给的server_name_callback回调 SSLContext.set_servername_callback()将获取SSLObject 实例而不是SSLSocket实例作为其第一个参数。

与使用有关的一些注意事项SSLObject

  • a上的所有IO SSLObject都是非阻塞的。这意味着,例如read()SSLWantReadError如果它需要的数据多于传入的BIO可用数据,则会引发一个 数据。
  • 没有wrap_bio()类似的模块级调用 wrap_socket()。一个SSLObject总是通过创建SSLContext

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

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

ssl.MemoryBIO

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

pending

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

eof

一个布尔值,指示存储器BIO在文件末尾位置是否是当前的。

readn = -1 

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

writebuf 

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

返回值是写入的字节数,总是等于buf的长度。

write_eof()

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

SSL会话

版本3.6中的新功能。

ssl.SSLSession

使用的Session对象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 自己调用构造函数来创建SSL上下文,则默认情况下不会启用证书验证或启用主机名检查。如果您这样做,请阅读以下段落以获得良好的安全级别。

手动设置

验证证书

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_CLIENT或 PROTOCOL_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()方法在协商SSL会话时启用密码微调 。从Python 3.2.3开始,ssl模块默认禁用某些弱密码,但您可能希望进一步限制密码选择。请务必阅读OpenSSL关于密码列表格式的文档。如果要检查给定密码列表启用了哪些密码,请使用 SSLContext.get_ciphers()或在系统上执行命令。openssl ciphers

多处理

如果将此模块用作多处理应用程序的一部分(例如使用multiprocessingconcurrent.futures模块),请注意OpenSSL的内部随机数生成器无法正确处理分叉进程。如果应用程序使用任何SSL功能,则应用程序必须更改父进程的PRNG状态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.session并且SSLSession 与TLS 1.3不兼容。
  • 在初始握手期间,也不再验证客户端证书。服务器可以随时请求证书。客户端在从服务器发送或接收应用程序数据时处理证书请求。
  • 尚不支持TLS 1.3功能,如早期数据,延迟TLS客户端证书请求,签名算法配置和密钥更新。

LibreSSL支持

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

  • LibreSSL> = 2.6.1不再支持NPN。这些方法 SSLContext.set_npn_protocols()SSLSocket.selected_npn_protocol()不可用。
  • SSLContext.set_default_verify_paths() 忽略env vars SSL_CERT_FILE 和 SSL_CERT_PATH虽然get_default_verify_paths()仍然报道他们。

也可以看看

类 socket.socket

基础socket类的文档

SSL / TLS强加密:简介

Apache HTTP Server文档介绍

RFC 1422:Internet电子邮件的隐私增强:第二部分:基于证书的密钥管理

史蒂夫肯特

RFC 4086:安全性的随机性要求

Donald E.,Jeffrey I. Schiller

RFC 5280:Internet X.509公钥基础结构证书和证书吊销列表(CRL)配置文件

D.库珀

RFC 5246:传输层安全性(TLS)协议版本1.2

T. Dierks等。人。

RFC 6066:传输层安全性(TLS)扩展

D. Eastlake

IANA TLS:传输层安全性(TLS)参数

IANA

RFC 7525:安全使用传输层安全性(TLS)和数据报传输层安全性(DTLS)的建议

IETF

Mozilla的服务器端TLS建议

Mozilla的

转载于:https://my.oschina.net/u/3612528/blog/3050941

你可能感兴趣的:(操作系统,网络,python)