
本文详解如何通过 urllib3 底层 ssl 套接字访问并解析远程 https 服务器的公钥证书,包括 pem 字典格式与 der 二进制格式两种获取方式,并演示如何用 cryptography 库进一步解析证书信息。
本文详解如何通过 urllib3 底层 ssl 套接字访问并解析远程 https 服务器的公钥证书,包括 pem 字典格式与 der 二进制格式两种获取方式,并演示如何用 cryptography 库进一步解析证书信息。
urllib3 本身未提供高层 API 直接暴露服务器证书,但其底层基于 Python 标准库的 ssl.SSLSocket,因此可通过访问连接对象的底层套接字,调用 getpeercert() 方法安全、可靠地提取证书信息。该方法支持两种返回形式:结构化字典(binary_form=False)和原始 DER 编码字节(binary_form=True),分别适用于快速检查与深度解析。
以下是一个完整、可运行的示例:
from urllib3.connection import HTTPSConnection
from cryptography.x509 import load_der_x509_certificate
from cryptography.hazmat.primitives import hashes
# 创建 HTTPS 连接(不发送任何 HTTP 请求,仅建立 TLS 握手)
conn = HTTPSConnection("example.com", server_hostname="example.com")
conn.connect()
# 获取底层 SSL 套接字
ssl_socket = conn.sock
# 方式 1:获取人类可读的证书信息字典(含 subject、issuer、notBefore、notAfter 等)
cert_dict = ssl_socket.getpeercert(binary_form=False)
print("证书基本信息(字典格式):")
print(f"主题 (Subject): {cert_dict['subject']}")
print(f"颁发者 (Issuer): {cert_dict['issuer']}")
print(f"有效期至: {cert_dict['notAfter']}")
# 方式 2:获取原始 DER 编码证书(可用于高级操作)
der_cert_bytes = ssl_socket.getpeercert(binary_form=True)
x509 = load_der_x509_certificate(der_cert_bytes)
print(f"\n证书序列号: {x509.serial_number}")
print(f"签名算法: {x509.signature_algorithm_oid._name}")
print(f"公钥长度: {x509.public_key().key_size} bits")
⚠️ 注意事项:
-
HTTPSConnection.connect()仅建立 TLS 连接,不会自动执行 HTTP 请求;如需后续发请求,应配合HTTPConnectionPool或PoolManager使用,或手动调用conn.request(); -
getpeercert()必须在connect()成功后调用,否则conn.sock为None; - 若启用证书验证(默认开启),确保系统信任根证书,否则连接可能失败;若需跳过验证(仅限测试),可传入
cert_reqs='CERT_NONE'(不推荐用于生产); -
binary_form=True返回的是标准 DER 格式,可直接交由cryptography、OpenSSL等库处理,支持指纹计算、扩展字段解析、签名验证等高级功能。
综上,虽然 urllib3 没有“开箱即用”的 .get_server_certificate() 方法,但借助其透明的 SSL 封装机制,开发者可以精准控制证书获取时机与解析粒度,兼顾简洁性与灵活性,是实现证书审计、TLS 指纹识别或自定义证书校验逻辑的理想基础。











