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

Python访问HTTPS接口时verify参数引发SSL错误求助

问题

尝试通过Python访问指定URL时遇到两种错误:

  • 设置verify=False时,报错:ValueError: Cannot set verify_mode to CERT_NONE when check_hostname is enabled.
  • 设置verify=True时,报错:Max retries exceeded with url: /api/search/users?employeesOnly=true&pid=g453942*&surname=y*&name=x* (Caused by SSLError(SSLError(9, '[SSL] PEM lib (_ssl.c:4044)')))

但浏览器访问该URL完全正常,且已导入证书,附上代码:

from flask import Flask

app = Flask(__name__)

import requests
import os
from OpenSSL import crypto

@app.route("/abc")
def home():
    url = 'https://myurl.com/api/search/users?employeesOnly=true&pid=g453942*&surname=y*&name=x*'
    pkcs12_filename = r"C:\Users\user16\Downloads\certificate_TEST2.p12"
    pkcs12_password = 'pass123'

    p12 = crypto.load_pkcs12(open(pkcs12_filename, 'rb').read(), pkcs12_password.encode())

    # PEM formatted private key
    k = crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())

    key_path = os.path.join(os.getcwd(), "myKey.key")
    cert_path = os.path.join(os.getcwd(), "myCert.crt")
    fkey = open(key_path, 'wb')
    fkey.write(k)
    fkey.close()

    # PEM formatted certificate
    c = crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())
    fcert = open(cert_path, 'wb')
    fcert.write(c)
    fcert.close()

    result = requests.get(url, verify=False, cert=(key_path, cert_path))


    return result


app.run(debug=True)

原因分析与解决方案

1. verify=False时的错误

这个错误是因为使用客户端证书的同时设置verify=False,底层SSL上下文默认开启了check_hostname,但verify=False会把verify_mode设为CERT_NONE,两者配置冲突导致报错。

解决办法:
不要同时混用客户端证书和verify=False,优先解决服务端证书信任问题后使用verify=True;如果临时需要关闭验证,得手动创建SSL上下文并关闭check_hostname,但不推荐生产环境这么做。

2. verify=True时的错误

报错SSL PEM lib主要是以下几个原因:

  • 客户端证书不完整:你只导出了用户证书,但PKCS12文件里通常包含完整的证书链(根CA、中间CA证书),浏览器会自动调用系统信任的CA链,但Python的requests不会,必须手动提供完整链。
  • 证书格式或匹配问题:导出的PEM证书可能存在格式错误,或者私钥与证书不匹配。
  • CA信任不兼容:浏览器使用系统信任存储,而requests默认用自己的CA bundle,可能不包含服务端的根CA证书。

具体修复步骤:

  1. 导出完整证书链:修改代码中导出证书的逻辑,把PKCS12里的用户证书和CA证书链合并到同一个PEM文件:
    # 导出用户证书
    c = crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())
    # 导出CA证书链并追加到用户证书后
    ca_certs = p12.get_ca_certificates()
    if ca_certs:
        for ca in ca_certs:
            c += crypto.dump_certificate(crypto.FILETYPE_PEM, ca)
    # 保存包含完整链的证书文件
    fcert = open(cert_path, 'wb')
    fcert.write(c)
    fcert.close()
    
  2. 指定信任的CA文件:把合并后的证书文件路径传给verify参数,替代True:
    result = requests.get(url, verify=cert_path, cert=(key_path, cert_path))
    
  3. 清理临时文件:每次请求生成的key和cert文件建议用完删除,避免重复生成导致冲突:
    os.remove(key_path)
    os.remove(cert_path)
    

浏览器能正常访问的原因:

  • 浏览器自动调用系统信任的CA证书链,无需手动指定;
  • 浏览器会自动解析PKCS12文件中的完整证书链,而你的代码只导出了用户证书,缺少中间/根CA导致Python无法验证服务端证书。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:31:19