python网络踩坑系列|requests/urllib sslerror 完整排查与解决方案
一、什么是 sslerror
sslerror 是 python 在 https 请求过程中 ssl/tls 握手失败抛出的异常。
底层来源于 openssl 库,requests、urllib、aiohttp 都会抛出该类错误。
常见报错片段:
requests.exceptions.sslerror: httpsconnectionpool(...): max retries exceeded with url: ...
caused by sslerror(sslcertverificationerror(1, '[ssl: certificate_verify_failed] certificate verify failed: unable to get local issuer certificate (_ssl.c:1002)'))
还有:证书过期、证书域名不匹配、ssl版本不兼容、ca证书缺失、代理导致ssl握手失败等。
核心本质:python客户端无法验证服务端ssl证书合法性,ssl握手阶段直接断开。
二、常见产生sslerror的场景
- 目标网站使用自签名证书、内网测试证书,没有公共ca签发
- python内置ca证书库缺失 / 损坏(windows/macos编译安装python高频坑)
- 网络存在代理、中间人抓包工具(fiddler、charles)篡改证书
- 服务端ssl/tls版本过低,和客户端openssl版本不兼容
- 系统时间错误,证书判定过期
- 请求url写错,把http写成https,服务端不支持https
三、方案1:临时关闭证书校验(开发调试用,生产不推荐)
安全警告:关闭校验会丧失证书校验能力,存在中间人劫持风险,仅限内网、调试环境,禁止线上业务直接使用。
requests 关闭证书校验
import requests
# verify=false 关闭证书校验
resp = requests.get("https://xxx.com", verify=false)
print(resp.text)
关闭后会输出大量 insecurerequestwarning 警告,可以屏蔽警告:
import requests
from requests.packages.urllib3.exceptions import insecurerequestwarning
requests.packages.urllib3.disable_warnings(insecurerequestwarning)
resp = requests.get("https://xxx.com", verify=false)
urllib3 / urllib
import urllib.request
import ssl
# 创建不校验证书的上下文
ctx = ssl.create_default_context()
ctx.check_hostname = false
ctx.verify_mode = ssl.cert_none
req = urllib.request.request("https://xxx.com")
with urllib.request.urlopen(req, context=ctx) as r:
print(r.read())
aiohttp
import aiohttp
import asyncio
async def demo():
# 关闭ssl校验
connector = aiohttp.tcpconnector(ssl=false)
async with aiohttp.clientsession(connector=connector) as session:
async with session.get("https://xxx.com") as resp:
print(await resp.text())
asyncio.run(demo())
重点提醒:verify=false 只是绕过报错,没有真正修复证书问题,生产环境严禁使用。
四、方案2:指定ca证书文件(推荐,正式解决方案)
当目标是自签名证书,把服务端的 .crt / .pem ca根证书导出,在请求时指定证书路径。
requests 指定ca
import requests
# 传入本地根证书pem路径
resp = requests.get("https://xxx.com", verify="./ca-root.pem")
也可以给session全局设置,后续所有请求生效:
import requests
session = requests.session()
session.verify = "./ca-root.pem"
resp = session.get("https://xxx.com")
五、方案3:修复python本地ca证书库
很多情况不是网站证书问题,是python找不到ca证书。
查看requests使用的ca路径
requests依赖 certifi 包维护一套内置ca根证书集合。
import certifi print(certifi.where())
输出就是ca.pem文件路径。
升级 certifi 包,更新根证书列表
pip install -u certifi
macos特殊坑:python安装后需要手动执行证书安装脚本
# python3.12示例,根据版本替换 /applications/python\ 3.12/install\ certificates.command
windows编译安装python,部分版本会缺失ca链,优先重装官方python,不要用精简版。
六、方案4:ssl/tls版本兼容问题
报错包含 ssl_error_unsupported_version,代表服务端ssl版本老旧,openssl新版本不再支持。
可以手动创建ssl上下文,调低允许的协议版本(谨慎,安全性下降)
import ssl
import requests
from requests.adapters import httpadapter
from urllib3.poolmanager import poolmanager
class ssladapter(httpadapter):
def init_poolmanager(self, connections, maxsize, block=false):
ctx = ssl.create_default_context()
ctx.options |= 0x4 # op_legacy_server_connect,兼容老旧服务端
self.poolmanager = poolmanager(num_pools=connections,
maxsize=maxsize,
block=block,
ssl_context=ctx)
session = requests.session()
session.mount("https://", ssladapter())
resp = session.get("https://old-server.com")
openssl3.0之后默认拒绝很多老旧不安全tls版本,内网老旧设备接口很容易触发该错误。
七、方案5:代理、抓包工具导致sslerror
本地开启fiddler、charles抓https,python请求会报证书错误:
- 方式a:把抓包工具根证书导入certifi的ca.pem
- 方式b:调试阶段临时设置
verify=false - 关闭代理环境变量,避免python走到错误代理
import os # 清除代理 os.environ["http_proxy"] = "" os.environ["https_proxy"] = ""
八、排查步骤模板(线上排错按顺序执行)
- 检查系统时间,时间不对直接导致证书校验失败。
- 浏览器访问目标url,确认浏览器是否报证书错误,判断是服务端证书问题还是python客户端问题。
- 升级
certifi、requests、urllib3版本。 - 测试:
verify=false请求是否成功。- 如果 verify=false 请求正常:确定是证书校验问题。
- 正式环境:导入自签名ca证书,指定verify=pem路径。
- 调试:临时关闭校验。
- 如果 verify=false 依旧报错:大概率tls版本不兼容、网络代理、防火墙拦截。
- 如果 verify=false 请求正常:确定是证书校验问题。
- 打印完整堆栈,区分是
certificate_verify_failed还是版本不兼容错误。
九、开发规范与避坑
生产禁止全局 verify=false,会引入安全漏洞;自签名内网服务,优先使用指定ca证书文件。
不要使用精简版python,容易缺失openssl与ca证书。
容器化部署python服务,镜像务必安装ca‑certificates包。
# alpine示例 run apk add ca-certificates
长连接session尽量复用自定义ssl上下文,不要每次请求新建上下文。
出现sslerror不要无脑直接关闭校验,先定位根因。
十、常见错误速查表
| 报错关键字 | 根因 | 处理思路 |
|---|---|---|
| certificate_verify_failed | 证书校验失败 | ca缺失、自签名证书;指定pem或者升级certifi |
| ssl_error_unsupported_version | tls版本不匹配 | 自定义ssl上下文开启兼容选项 |
| ssl: certificate_expired | 证书过期 | 服务端更新证书,客户端无法修复 |
| hostname mismatch | 证书域名不匹配 | 证书域名与访问域名不一致 |
总结
- sslerror绝大多数是ssl证书校验失败,由openssl底层抛出。
verify=false只是调试手段,生产环境不要使用;自签名证书优先传入ca根证书文件。- certifi包维护python内置ca根证书,升级certifi可以解决大部分公网证书链问题。
- 内网老旧设备会遇到tls版本兼容问题,可以自定义ssl上下文做兼容。
- 抓包代理、系统时间错误、容器缺少ca‑certificates,也是高频诱因。
以上就是python中requests/urllib请求sslerror错误完整排查与解决方案的详细内容,更多关于python sslerror错误处理的资料请关注代码网其它相关文章!
发表评论