如何在不禁用的前提下解决requests代理请求的InsecureRequestWarning
问题:requests通过HTTPS代理时的InsecureRequestWarning无法消除
我用Python 3的requests模块向远程REST服务器请求数据,请求必须经过一个要求SSL证书的代理。我已经持有对应的证书——这个证书是用我生成的密钥创建、经代理管理员签名的,另外因为代理密钥是自签名的,他们还提供了一份PEM格式的CA证书包。
我的请求代码如下:
import requests url='http://rest.lab/' proxies = { 'http': 'https://proxy.lab/', 'https': 'https://proxy.lab/' } resp= requests.get(url, timeout=30, proxies=proxies, cert=('./local.cert', './local.key'), verify='./ca.pem')
连接能正常工作并返回预期数据,但始终无法消除InsecureRequestWarning警告:
/usr/local/lib/python3.10/site-packages/urllib3/connectionpool.py:1045: InsecureRequestWarning: Unverified HTTPS request is being made to host 'proxy.lab'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
我看过警告里的链接,但内容都是关于Mozilla根证书包的,对我没用,因为代理服务器没用到任何外部CA。网上搜出来的大多是禁用或隐藏警告的方法,但我不想这么做——警告应该被修复而不是掩盖。
我找不到让requests模块使用提供的CA证书来验证代理的方法,也了解过auth参数,但它好像只用于端点认证,和代理认证无关。
有没有不用隐藏警告的解决办法?
解决方法
问题核心:你当前设置的verify参数仅作用于**目标服务器(rest.lab)的SSL验证,并未覆盖代理服务器(proxy.lab)**的SSL验证逻辑。requests默认会分开处理目标服务器和代理的SSL校验,以下是两种无需隐藏警告的修复方案:
方案1:通过环境变量全局指定CA证书
设置REQUESTS_CA_BUNDLE环境变量,让requests将指定的CA证书用于所有SSL验证(包括代理):
# Linux/macOS终端中先执行 export REQUESTS_CA_BUNDLE="./ca.pem" # 再运行你的Python脚本 python your_script.py
方案2:自定义HTTPAdapter(更灵活)
如果不想修改环境变量,可以自定义HTTPAdapter,在创建连接池时明确指定用于验证代理的CA证书:
import requests from urllib3.poolmanager import PoolManager from urllib3.util.ssl_ import create_urllib3_context class ProxyCAAdapter(requests.adapters.HTTPAdapter): def __init__(self, ca_cert_path, *args, **kwargs): self.ca_cert = ca_cert_path super().__init__(*args, **kwargs) def init_poolmanager(self, *args, **kwargs): # 创建SSL上下文并加载代理的CA证书 ssl_context = create_urllib3_context() ssl_context.load_verify_locations(self.ca_cert) kwargs['ssl_context'] = ssl_context return super().init_poolmanager(*args, **kwargs) # 初始化Session并挂载自定义Adapter url = 'http://rest.lab/' proxies = { 'http': 'https://proxy.lab/', 'https': 'https://proxy.lab/' } session = requests.Session() # 为HTTP和HTTPS协议都挂载Adapter session.mount('http://', ProxyCAAdapter('./ca.pem')) session.mount('https://', ProxyCAAdapter('./ca.pem')) # 发起请求 resp = session.get(url, timeout=30, proxies=proxies, cert=('./local.cert', './local.key'))
补充说明
cert参数是你提供给代理的客户端证书,用于代理验证你的身份,而非你验证代理的证书verify参数默认仅校验目标服务器的SSL证书,无法直接作用于代理,这是导致警告出现的根本原因
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

