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

如何解决使用http.client.HTTPSConnection时的主机名不匹配错误?

Python2与Python3中httplib HTTPS连接差异问题排查

问题背景

原有程序基于httplib/http.client实现请求发送,在Python2.7下运行正常,但切换到Python3后出现HTTPS连接异常:

  • HTTP协议场景:Python2与Python3均能正常工作
  • HTTPS协议场景:Python3连接部分命名服务器失败,抛出错误:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for '{server name}'. (_ssl.c:1123)

运行环境覆盖:OS X Python3.9.6、AWS Linux Python3.8.5、Python2.7.18;IT部门为云内命名服务器配置了通配符证书,且已确认问题服务器的证书与Python3可正常连接的服务器证书一致。

相关代码片段:

模块导入

if PY_VERSION >= 3:
    import http.client as httplib
else:
    import httplib

连接类型定义

if self.protocol == 'http':
    self.httpConn = httplib.HTTPConnection
elif self.protocol == 'https':
    self.httpConn = httplib.HTTPSConnection

连接初始化

if self.protocol == 'https':
    self.ssl_context = ssl.create_default_context()
self.the_conn = self.httpConn(self.site)

需求:明确Python2到Python3的行为变更原因,并提供兼容两个版本的解决方案(不可依赖requests模块,因Python2环境无该依赖)


问题核心原因

1. HTTPS主机名验证逻辑强制开启

Python2.7的httplib.HTTPSConnection默认不执行主机名验证——即使证书的CN(通用名称)或SAN(主题备用名称)与目标服务器域名不匹配,连接仍能成功建立。

而Python3.2+的http.client.HTTPSConnection默认强制开启主机名验证:使用ssl.create_default_context()创建的上下文会自动绑定主机名验证回调,严格校验证书中的域名是否与连接目标完全匹配。如果通配符证书不符合规范(比如*.example.com仅支持一级子域,而实际连接的是多级子域a.b.example.com),就会触发主机名不匹配错误。

2. SSL上下文默认配置差异

Python2中HTTPSConnection使用的默认SSL上下文未启用证书验证逻辑;Python3中ssl.create_default_context()默认启用CERT_REQUIRED验证模式,同时强制校验主机名与证书的匹配性。


兼容解决方案

方案1:自定义主机名验证逻辑(推荐,兼顾安全与兼容性)

针对Python3调整SSL上下文的验证规则,适配通配符证书的匹配需求;Python2保持原有逻辑或补充基础验证:

import ssl
if PY_VERSION >= 3:
    import http.client as httplib
else:
    import httplib

# 初始化连接类型
if self.protocol == 'http':
    self.httpConn = httplib.HTTPConnection
elif self.protocol == 'https':
    self.httpConn = httplib.HTTPSConnection

# 建立连接
if self.protocol == 'https':
    if PY_VERSION >= 3:
        # 创建默认SSL上下文,自定义主机名验证规则
        self.ssl_context = ssl.create_default_context()
        # 关闭默认验证回调,改用自定义逻辑
        self.ssl_context.check_hostname = False
        self.ssl_context.verify_mode = ssl.CERT_REQUIRED
        
        self.the_conn = self.httpConn(self.site, context=self.ssl_context)
        self.the_conn.connect()
        
        # 自定义通配符匹配逻辑(支持多级子域场景)
        def custom_match_hostname(cert, hostname):
            from ssl import CertificateError
            # 优先取SAN中的域名,无则取CN
            cert_domains = []
            if 'subjectAltName' in cert:
                cert_domains = [item[1] for item in cert['subjectAltName'] if item[0] == 'DNS']
            else:
                cert_domains = [item[0][1] for item in cert['subject'] if item[0][0] == 'commonName']
            
            for domain in cert_domains:
                if domain == hostname:
                    return
                if domain.startswith('*.'):
                    base_domain = domain[2:]
                    # 匹配多级子域(如*.example.com 匹配 a.b.example.com)
                    if hostname.endswith(f'.{base_domain}') or hostname == base_domain:
                        return
            raise CertificateError(f"Hostname {hostname} does not match certificate domains {cert_domains}")
        
        # 手动执行主机名验证
        custom_match_hostname(self.the_conn.sock.getpeercert(), self.site)
    else:
        # Python2环境保持原有连接逻辑,可选开启基础证书验证
        self.the_conn = self.httpConn(self.site)
else:
    self.the_conn = self.httpConn(self.site)

方案2:临时关闭主机名验证(仅内部可信环境使用)

若为完全可信的内部环境,可临时关闭主机名验证(注意:会降低连接安全性):

if self.protocol == 'https':
    if PY_VERSION >= 3:
        self.ssl_context = ssl.create_default_context()
        # 关闭主机名验证,保留证书链验证
        self.ssl_context.check_hostname = False
        self.the_conn = self.httpConn(self.site, context=self.ssl_context)
    else:
        self.the_conn = self.httpConn(self.site)
else:
    self.the_conn = self.httpConn(self.site)

补充说明

  • 优先检查通配符证书是否符合RFC规范:标准通配符*.example.com仅支持一级子域,若需匹配多级子域,证书需配置对应多级通配符(如*.b.example.com)或在SAN中添加具体的多级子域名。
  • Python2.7.9及以上版本也支持通过context参数传入SSL上下文,可进一步统一跨版本的验证逻辑。

内容的提问来源于stack exchange,提问作者Christopher Biessener

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:07:10