如何为requests客户端和flask-restful服务端配置TLS1.2自签名证书验证
TLS连接报错修复方案
核心错误原因说明
你遇到的CERTIFICATE_VERIFY_FAILED报错,和证书扩展名没有直接关系,主要由三个常见原因导致:
1 证书扩展名认知纠正
.crt、.pem都是证书的常用扩展名,二者没有本质区别,只和编码格式有关:
- 文本格式的PEM编码证书,打开可以看到
-----BEGIN CERTIFICATE-----前缀,openssl默认生成的ca.crt、server.crt大多是这种格式,直接给requests的verify参数使用即可,不需要修改后缀。 - 二进制格式的DER编码证书相对少见,需要转成PEM格式才能给requests使用。
你之前尝试把client.pem填到verify字段是错误的:verify参数填的是用来校验服务端证书的CA根证书,client证书是用来给服务端校验客户端身份的,需要放到cert参数里。
2 服务端证书地址匹配校验
生成server.crt时填写的Common Name(通用名)必须和客户端访问的地址完全一致:
- 如果客户端用IP访问服务端,Common Name需要填服务端的公网/内网IP
- 如果客户端用域名访问,Common Name需要填对应域名
新的TLS库默认强制校验SAN(主题备用名),如果需要支持多个访问地址,生成server证书时需要添加SAN扩展配置。
你可以用以下命令快速校验证书匹配性:
openssl s_client -connect 你的服务端地址:8000 -CAfile ca.crt
如果输出中包含Verify return code: 0 (ok),说明证书本身和CA信任链没有问题,否则需要重新生成服务端证书。
3 双向TLS配置修正
你当前服务端代码中开启了VERIFY_USER = True,对应配置context.verify_mode = ssl.CERT_REQUIRED,这是开启了双向TLS验证:服务端也会要求客户端出示由同一CA签发的客户端证书,你当前的客户端代码没有携带客户端证书,会被服务端主动拒绝连接。
可以根据你的安全需求二选一调整:
方案A:仅保留客户端对服务端的验证(满足基础安全需求)
把服务端代码中的VERIFY_USER改为False,重启服务端即可,客户端代码不需要修改。
方案B:保留双向TLS验证(更高安全性)
- 用现有CA签发客户端证书,得到client.crt和client.key两个文件
- 调整客户端请求代码,添加客户端证书参数:
response = requests.get("https://[url of server]:8000/helloworld", verify='ca.crt', cert=('client.crt', 'client.key'))
快速验证流程
- 先将服务端
VERIFY_USER设为False重启 - 用上述openssl命令测试连接,确认返回验证成功
- 运行客户端代码,即可正常收到返回结果
内容的提问来源于stack exchange,提问作者Nolan Davenport
相关产品推荐
相关产品推荐

