使用PEM证书调用TLS加密REST API报SSL验证错误如何解决
问题原因与修复方案
你出现报错的核心原因是参数使用逻辑混淆、传参方式错误,具体修正方案如下:
- 参数作用混淆:
verify参数的作用是校验服务端返回的SSL证书合法性,你将用于客户端身份认证的pem文件传给verify自然会触发校验失败。客户端证书认证需要使用cert参数传入证书路径。 - 请求传参错误:
params是用来构造URL查询参数的配置项,你把POST请求体序列化后传给params相当于把整个请求体塞到了URL中,完全不符合接口调用规则。POST传JSON格式请求体直接使用json参数传入字典即可,不需要手动执行json.dumps。 - TLS版本适配:对方接口指定仅支持TLS1.1/1.2,需要自定义HTTP适配器强制指定TLS版本,避免默认协商到不支持的协议版本。如果服务端使用自签证书,不需要校验服务端证书合法性的话可以将
verify设为False,如果有服务端CA证书也可以将verify设置为CA证书路径。
修正后代码示例
import requests as req from requests.adapters import HTTPAdapter import ssl import urllib3 # 关闭不校验服务端证书时的告警 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # 自定义适配器强制使用TLS 1.2(如对方仅支持1.1可修改为TLSv1_1) class TLS12Adapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): context = ssl.create_default_context() context.min_version = ssl.TLSVersion.TLSv1_2 kwargs["ssl_context"] = context return super().init_poolmanager(*args, **kwargs) url = 'https://url.com/call' certificate_file = "C:/certs/cert.pem" headers = {"Content-Type": "application/json"} req_body ={ "network":{ "network_id": 12345 }, "branch":{ "branch_id": 12345, }, "export_period":{ "start_date_time": "16-11-2021 00:00:00", "end_date_time": "17-11-2021 00:00:00" } } # 挂载TLS适配器初始化会话 sess = req.Session() sess.mount("https://", TLS12Adapter()) # 发起请求,cert传客户端证书,verify关闭服务端证书校验 # 如pem内私钥加密,cert参数改为元组 (certificate_file, "私钥密码") response = sess.post(url, headers=headers, json=req_body, cert=certificate_file, verify=False) print(response.status_code) print(response.text)
注意事项
- TLS1.1属于已废弃的不安全协议,优先和接口提供方确认是否支持TLS1.2及以上版本。
- 生产环境建议尽量拿到服务端的CA根证书传给
verify参数,避免关闭证书校验带来的安全风险。
内容的提问来源于stack exchange,提问作者TJB
相关产品推荐
相关产品推荐

