Python请求需SSL证书认证的网页遇错误,求助解决
问题:Python访问需SSL客户端证书认证的端点失败
操作步骤与错误情况
- 初始尝试用
urllib加载PKCS12证书:
import urllib urllib.request.urlopen("https://mywebpage.com/some/endpoint", cafile = "C:/Users/Me/path/to/my/cert.p12")
报错:
ssl.SSLError: [X509: NO_CERTIFICATE_OR_CRL_FOUND] no certificate or crl found (_ssl.c:4149)
- 转换PKCS12为PEM格式:
执行OpenSSL命令:
openssl pkcs12 -in "C:/Users/Me/path/to/my/cert.p12" -out "C:/Users/Me/path/to/my/cert.pem"
设置PKCS12和PEM密码一致后,尝试代码:
import urllib urllib.request.urlopen("https://mywebpage.com/some/endpoint", cafile = "C:/Users/Me/path/to/my/cert.pem")
报错:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)
验证证书加载:执行ssl.SSLContext().load_verify_locations(cafile = "C:/Users/Me/path/to/my/cert.pem")无报错,证书信息已加载。
- 尝试使用
certifi解决Windows下OpenSSL版本问题:
import ssl import certifi from urllib import request request.urlopen("https://mywebpage.com/some/endpoint", context = ssl.create_default_context(cafile = certifi.where()))
报错:
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1007)
问题分析与解决方案
核心问题
你混淆了**CA证书(用于验证服务器合法性)和客户端证书(用于服务器验证你的身份)**的用途:
cafile参数是用来指定信任的CA证书,用于校验服务器证书是否合法;- 浏览器弹出的证书选择窗口,是要求你发送客户端证书给服务器,属于双向SSL认证场景,这部分你之前的代码完全没配置。
正确操作步骤
- 确保PEM文件包含客户端证书和私钥
转换PKCS12时,要导出包含证书和私钥的PEM文件,执行命令时加上-nodes参数(避免私钥加密,若需加密可去掉该参数,后续加载时提供密码):
openssl pkcs12 -in "C:/Users/Me/path/to/my/cert.p12" -out "C:/Users/Me/path/to/my/client_cert.pem" -nodes
- 创建SSL上下文并加载客户端证书
用ssl.SSLContext配置双向认证,同时指定信任的CA证书(服务器证书是自定义CA签发的需指定对应CA文件,公网证书可直接用默认信任链):
import ssl from urllib import request # 创建SSL上下文,用于服务器认证 context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) # 加载客户端证书(若PEM有密码,添加password参数,如password=b"your_cert_password") context.load_cert_chain(certfile="C:/Users/Me/path/to/my/client_cert.pem") # 若服务器用自定义CA签发,需指定CA证书;公网证书可注释此行 # context.load_verify_locations(cafile="path/to/server_trusted_ca.pem") # 发起请求 response = request.urlopen("https://mywebpage.com/some/endpoint", context=context) print(response.read())
- 常见问题排查
- 若仍报
unable to get local issuer certificate:确认服务器的CA证书已加入信任链,或load_verify_locations指定了正确的CA文件; - 若报
handshake failure:检查客户端证书是否包含完整链(含中间证书)、是否未过期,或尝试调整SSL版本(如context.options |= ssl.OP_NO_TLSv1_3,根据服务器支持情况修改); - 确认客户端证书的CN/SAN字段符合服务器的验证要求。
内容的提问来源于stack exchange,提问作者Woody1193
相关产品推荐
相关产品推荐

