You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Curl可访问自签名证书内部地址,Python Requests遇SSL验证失败

requests验证自签名CA证书失败但curl成功的原因分析

问题场景

访问内部自签名证书地址时,curl https://myhost.internal --cacert ./mycert.crt返回200,但使用Python requests库:

import requests
requests.get('https://myhost.internal', verify='./mycert.crt')

抛出SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:727)'),subprocess调用curl正常,关闭验证(verify=False)也能成功,但不符合安全要求。

可能的原因

1. 证书格式不兼容

curl对证书格式的容错性更高,可自动识别并处理DER/PEM格式,甚至忽略文件内的非证书内容。但requests依赖的urllib3/ssl模块要求证书必须是标准PEM格式(文件开头包含-----BEGIN CERTIFICATE-----)。如果你的mycert.crt是DER二进制格式,或格式存在异常,requests会验证失败。

验证方法:

openssl x509 -in ./mycert.crt -text

若命令报错,说明格式有问题,可转换为PEM格式:

openssl x509 -inform der -in ./mycert.crt -out ./mycert_pem.crt

2. 证书链不完整

当服务器返回的证书由中间CA签发时,curl会自动从--cacert指定的文件中查找缺失的中间证书,补全证书链。但requests要求提供的CA文件必须包含完整的信任链(从服务器证书的上级中间CA到根CA),否则会因无法追溯到信任根而验证失败。

解决方法:
将中间CA证书与根CA证书按顺序拼接至同一个.crt文件(根CA放在最后),再提供给verify参数。

3. SSL验证逻辑版本差异

Python的requests依赖系统OpenSSL库,不同版本的OpenSSL对证书验证规则不同:

  • 部分Python版本(如3.7+)默认要求服务器证书必须包含subjectAltName字段,仅靠CN字段匹配会被拒绝;
  • curl使用的OpenSSL版本可能仍允许CN字段匹配,因此能成功建立连接。

验证方法:
查看服务器证书的subjectAltName字段:

openssl s_client -connect myhost.internal:443 | openssl x509 -noout -text

若输出中无X509v3 Subject Alternative Name,则需重新签发包含该字段的证书。

4. 相对路径解析错误

requests的verify参数使用相对路径时,路径是相对于Python脚本的当前工作目录,而非脚本文件所在目录。如果运行Python脚本的目录与执行curl时的目录不同,./mycert.crt会指向错误路径,导致无法加载证书。

解决方法:
使用证书的绝对路径,例如:

requests.get('https://myhost.internal', verify='/home/user/mycert.crt')

5. 证书文件权限不足

curl对证书文件的权限要求较低,但Python运行进程的用户可能没有mycert.crt的读取权限,导致无法加载证书,进而触发验证失败。

解决方法:
调整证书文件权限,确保运行Python的用户有读权限:

chmod 644 ./mycert.crt

内容的提问来源于stack exchange,提问作者Djoby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:42:24