Requests 2.32版本cert参数未清除导致跨请求证书残留问题
Requests 2.32版本中cert参数残留导致后续请求SSL错误的问题分析与解决
问题诊断
这是Requests 2.32版本引入的bug,并非你对概念的误解。问题根源在于该版本中全局复用的ssl_context对象在设置过客户端证书后未被正确重置,导致后续未指定cert参数的请求依然会携带之前的证书,触发服务器端的SSL验证错误。
原因分析
在Requests 2.32的requests/adapters.py实现里,默认SSL上下文被多个请求共享:
- 第一次发送不带
cert的请求时,上下文处于干净状态; - 发送带
cert的请求后,上下文被修改并缓存; - 后续不带
cert的请求复用了这个已被修改的上下文,错误携带之前的客户端证书,最终被服务器拒绝。
而使用Session时表现正常,是因为每个Session拥有独立的SSL上下文,不同请求的上下文不会互相污染——这其实符合Session隔离请求状态的设计初衷,只是和你之前的直觉相反。
解决方案
你可以选择以下几种可行方案:
- 降级到Requests 2.31.0版本:这是最直接的临时方案,回退到无此bug的版本:
pip install requests==2.31.0 - 为每个请求创建独立的Session:如果无法全局降级,可在每次请求时创建新Session,避免上下文复用:
import requests if __name__ == '__main__': url = 'https://auth.smaapis.de/oauth2/token' cert = ('example_cert.pem', 'example_cert_key.pem') # 第一个请求用独立Session with requests.Session() as session: response = session.post(url) print('Before Response: {} {}: {}\n'.format(response.status_code, response.reason, response.text)) # 带cert的请求用独立Session with requests.Session() as session: response = session.get('https://google.com', cert=cert) # 第三个请求用独立Session with requests.Session() as session: response = session.post(url) print('After Response: {} {}: {}\n'.format(response.status_code, response.reason, response.text)) - 手动重置SSL上下文:通过修改适配器的SSL上下文避免残留,这种方式需深入Requests内部实现,仅作为临时应急方案:
import requests from requests.adapters import HTTPAdapter def reset_ssl_context(): adapter = requests.adapters.HTTPAdapter() adapter.init_poolmanager() requests.sessions.default_adapters['https://'] = adapter # 在需要清除cert残留的请求前调用 reset_ssl_context()
后续跟进
该bug已被社区反馈,你可关注Requests官方仓库的修复进度,但目前优先采用降级或隔离Session的方案更稳妥。
内容的提问来源于stack exchange,提问作者C. Short
相关产品推荐
相关产品推荐

