Python urllib 报 SSL: CERTIFICATE_VERIFY_FAILED 怎么解决
urllib 的证书错误应依据 verify message 排查证书链、有效期与名称。安装 certifi 不会自动改变 urllib;显式配置可信 CA,并保持验证开启。
报错示例
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificate (_ssl.c:1002)>
含义:Python 的 ssl 模块在本地信任库中找不到签发对端证书的 CA。注意这与"证书本身过期/无效"是两类问题——需单独核实目标证书链,浏览器成功并不能证明 Python 所需链完整。
修复方法一:安装/升级 certifi
pip install --upgrade certifi
然后显式使用 certifi 提供的 CA 包:
import ssl, urllib.request, certifi
ctx = ssl.create_default_context(cafile=certifi.where())
data = urllib.request.urlopen('https://example.com', context=ctx).read()
修复方法二:macOS 官方安装包的专属步骤
从 python.org 下载的安装包不会自动接入系统钥匙串,需要执行:
open "/Applications/Python 3.12/Install Certificates.command"
(按实际 Python 版本调整目录名。)该脚本会安装 certifi 并建立 ssl 模块的默认信任路径,之后无需再手动指定 cafile。
修复方法三:企业内网/自签证书场景
如果目标站点用的是企业私有 CA 或自签证书:
- 从受控 IT/PKI 渠道取得 CA 证书并独立核验 SHA-256 指纹
- 指定它作为信任根:
ctx = ssl.create_default_context(cafile='/path/to/internal-ca.crt')
- 或者把 CA 追加进系统信任库(Linux 常见路径
/usr/local/share/ca-certificates/后执行update-ca-certificates)
修复方法四:更新系统 CA 包
Linux 服务器上系统 CA 包过旧也会导致校验失败:
# Debian/Ubuntu
apt update && apt install --only-upgrade ca-certificates
# RHEL/CentOS
yum update ca-certificates
千万不要这样做
不要使用 ssl._create_unverified_context() 或关闭主机名检查来绕过问题。它们会放弃服务身份验证,尤其不能用于获取依赖、凭据或业务数据。应修复证书链、名称、时间或信任来源,而不是让请求强行成功。
常见问题(FAQ)
Q:浏览器访问正常,只有 Python 报错,为什么?
A:浏览器和操作系统各自维护信任库且更新频繁,Python(尤其 macOS 官方包和精简 Docker 镜像)可能带着一份陈旧甚至为空的 CA 库。还可能是服务端中间链、代理或名称验证差异;检查具体错误,再决定是否需要更新或显式配置 CA。
Q:Docker 镜像里报这个错怎么处理?
A:精简镜像(alpine、slim)常缺 ca-certificates。在 Dockerfile 中补装:Debian 系 apt-get install -y ca-certificates,Alpine 用 apk add --no-cache ca-certificates,并确认 Python 能找到它们。
Q:certifi 已是最新还是失败?
A:检查是否处在企业代理(SSL 拦截)环境——代理会用自己的 CA 重签所有证书。需要把代理的根证书导入信任库,urllib/ssl 按 OpenSSL 默认路径可受 SSL_CERT_FILE 影响;REQUESTS_CA_BUNDLE 是 Requests 的配置,并不控制 urllib。显式传入受信 SSLContext 更清楚。
参考资料
本文依据官方资料核对,未进行现场运行测试;代码与配置示例需结合实际版本、权限和环境验证。