Nginx本地SSL终止时Python requests报CERTIFICATE_VERIFY_FAILED错误
根因分析
- 证书主机名配置缺失:生成自签名证书时所有交互项留空,导致证书的Common Name(CN)为空,且未添加Subject Alternative Name(SAN)扩展字段包含
localhost。现代TLS实现会强制校验证书与请求域名的匹配性,无有效主机名的证书即使被信任也无法通过校验,这也是你设置verify=False后仍然报主机名不匹配错误的原因。 - 证书路径不匹配:代码中
verify参数传入的证书路径为/etc/ssl/certs/proxypool.pem,但你实际生成的证书文件是/etc/ssl/certs/proxypool.crt,路径不一致会导致requests无法加载信任证书。
解决方案
步骤1:重新生成符合校验规则的自签名证书
先创建SAN扩展配置文件san.conf,解决证书主机名匹配问题:
[req] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn x509_extensions = v3_req [dn] CN = localhost [v3_req] subjectAltName = @alt_names basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1
执行openssl命令生成证书:
sudo openssl req -x509 -nodes -days 9999 -newkey rsa:2048 \ -keyout /etc/ssl/private/proxypool.key \ -out /etc/ssl/certs/proxypool.crt \ -config san.conf
生成pem格式证书供requests使用:
sudo cp /etc/ssl/certs/proxypool.crt /etc/ssl/certs/proxypool.pem
步骤2:重载Nginx配置
确认Nginx配置无误后执行重载生效:
sudo nginx -s reload
步骤3:验证请求代码
保持证书校验的请求代码如下,确认证书路径正确即可正常请求:
import requests proxies = { "http": "http://localhost", "https": "https://localhost" } response = requests.post( "https://api.ipify.org?format=json", proxies=proxies, verify="/etc/ssl/certs/proxypool.pem" ) print(response.json())
如果仅做临时测试不需要校验证书,可以使用以下代码同时关闭证书校验和主机名校验:
import requests import urllib3 from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager import ssl # 关闭SSL警告输出 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) class DisableHostnameCheckAdapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE kwargs["ssl_context"] = context return super().init_poolmanager(*args, **kwargs) session = requests.Session() session.mount("https://", DisableHostnameCheckAdapter()) proxies = { "http": "http://localhost", "https": "https://localhost" } response = session.post( "https://api.ipify.org?format=json", proxies=proxies, verify=False ) print(response.json())
内容的提问来源于stack exchange,提问作者Constantin
相关产品推荐
相关产品推荐

