Python3 requests如何通过TLS适配器设置自定义TLS扩展字段?
问题:Python3 requests库设置TLS扩展的最佳方案
我不确定是否可以、以及如何使用Python3的requests库设置TLS扩展。
下方代码实现了一个供Python3 requests使用的TLS适配器,可以在初始Client Hello报文中显式声明允许的加密套件。但Client Hello报文还可包含众多其他扩展(见代码下方的TLS扩展列表),我尝试在**kwargs和ssl_context中指定这些扩展但均未成功。
requests官方没有给出允许配置的选项列表,查阅HTTPAdapter的源码也没有找到设置TLS扩展的相关功能,请问使用requests设置TLS扩展的最佳方案是什么?
import ssl import requests from requests.adapters import HTTPAdapter from requests.packages.urllib3.poolmanager import PoolManager from requests.packages.urllib3.util import ssl_ CIPHERS = ( 'ECDHE-RSA-AES256-GCM-SHA384:' 'ECDHE-ECDSA-AES256-GCM-SHA384:' 'ECDHE-RSA-AES256-SHA384:' 'ECDHE-ECDSA-AES256-SHA384:' 'ECDHE-RSA-AES128-GCM-SHA256:' 'ECDHE-RSA-AES128-SHA256:' 'AES256-SHA' ) class TlsAdapter(HTTPAdapter): def __init__(self, ssl_options=0, **kwargs): self.ssl_options = ssl_options super(TlsAdapter, self).__init__(**kwargs) def init_poolmanager(self, *pool_args, **pool_kwargs): ctx = ssl_.create_urllib3_context(ciphers=CIPHERS, cert_reqs=ssl.CERT_REQUIRED, options=self.ssl_options) self.poolmanager = PoolManager(*pool_args, ssl_context=ctx, **pool_kwargs) s = requests.session() # 指定禁用TLS 1.0和TLS 1.1 adapter = TlsAdapter(ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1) s.mount("https://", adapter) s.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'} try: r = s.request('GET', 'https://google.com') print(r) except Exception as e: print(e)
TLS扩展列表
扩展名称 | 扩展十六进制编码 max_fragment_length | 0001 status_request | 0005 client_authz | 0007 server_authz | 0008 cert_type | 0009 supported_groups | 000a ec_point_formats | 000b signature_algorithms | 000d heartbeat | 000f application_layer_protocol_negotiation | 0010 status_request_v2 | 0011 client_certificate_type | 0013 server_certificate_type | 0014 token_binding | 0018 compress_certificate | 001b record_size_limit | 001c supported_versions | 002b psk_key_exchange_modes | 002d signature_algorithms_cert| 0032 channel_id | 5500
解决方案
requests本身没有封装TLS扩展的配置接口,所有TLS层面的配置都依赖底层的Python标准库ssl模块提供的能力,你可以在自定义适配器中生成ssl_context后,直接调用ssl模块的原生方法配置扩展即可,具体操作如下:
- 你当前自定义适配器中已经拿到了
ctx(即SSLContext实例),直接用SSLContext的官方方法配置对应扩展即可,不同扩展对应的配置方法不同,常见场景举例:- 配置ALPN扩展:调用
ctx.set_alpn_protocols(['h2', 'http/1.1']) - 配置支持的TLS版本扩展:调用
ctx.max_version = ssl.TLSVersion.TLSv1_3、ctx.min_version = ssl.TLSVersion.TLSv1_2 - 配置签名算法扩展:调用
ctx.set_ciphers()或者Python 3.10+提供的ctx.set_signature_algorithms()
- 配置ALPN扩展:调用
- 如果你需要配置
ssl模块没有提供封装方法的小众扩展,Python 3.10+提供了SSLContext.add_extension()方法,可以手动传入扩展的类型码、是否关键扩展、以及扩展的二进制内容,完全自定义扩展字段。 - 所有扩展配置完成后再将ctx传入PoolManager即可,不需要修改requests或urllib3的源码。
修改后的TlsAdapter示例代码(以配置ALPN扩展和支持的TLS版本为例):
class TlsAdapter(HTTPAdapter): def __init__(self, ssl_options=0, **kwargs): self.ssl_options = ssl_options super(TlsAdapter, self).__init__(**kwargs) def init_poolmanager(self, *pool_args, **pool_kwargs): ctx = ssl_.create_urllib3_context(ciphers=CIPHERS, cert_reqs=ssl.CERT_REQUIRED, options=self.ssl_options) # 新增TLS扩展配置 # 配置ALPN扩展,支持HTTP2和HTTP1.1 ctx.set_alpn_protocols(["h2", "http/1.1"]) # 配置仅支持TLS1.2和TLS1.3,对应supported_versions扩展 ctx.min_version = ssl.TLSVersion.TLSv1_2 ctx.max_version = ssl.TLSVersion.TLSv1_3 self.poolmanager = PoolManager(*pool_args, ssl_context=ctx, **pool_kwargs)
注:不同扩展对应的配置逻辑请参考Python官方ssl模块文档,部分老旧Python版本可能不支持部分扩展的配置,建议使用Python 3.8及以上版本。
内容的提问来源于stack exchange,提问作者I'm Root James
相关产品推荐
相关产品推荐

