Python验证证书SAN中IP与域名绑定配对的问题排查
Python 解决方案
首先确保安装依赖:
pip install cryptography ipaddress
你的问题大概率是没正确区分SAN中的DNS条目与IP地址条目,或是IP地址的字符串转换/比较逻辑有误。以下是准确验证配对的代码:
from cryptography import x509 from cryptography.hazmat.backends import default_backend import ipaddress # 预定义的域名-IP配对 REQUIRED_PAIRS = [ ("sub.example.com", "192.168.1.1"), ("test.example.com", "10.0.0.1") ] def load_certificate(cert_path): with open(cert_path, "rb") as f: cert_data = f.read() return x509.load_pem_x509_certificate(cert_data, default_backend()) def extract_san_entries(cert): san_ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName) san_entries = san_ext.value dns_names = [] ip_addresses = [] for entry in san_entries: if isinstance(entry, x509.DNSName): dns_names.append(entry.value) elif isinstance(entry, x509.IPAddress): # 统一IP地址的字符串格式 ip_str = str(ipaddress.ip_address(entry.value)) ip_addresses.append(ip_str) return dns_names, ip_addresses def validate_san_pairs(dns_names, ip_addresses): all_valid = True for domain, required_ip in REQUIRED_PAIRS: if domain not in dns_names: print(f"错误:域名 {domain} 不在证书SAN中") all_valid = False if required_ip not in ip_addresses: print(f"错误:域名 {domain} 对应的IP {required_ip} 不在证书SAN中") all_valid = False # 可选:检查是否存在多余SAN条目(需严格匹配时启用) extra_domains = set(dns_names) - {pair[0] for pair in REQUIRED_PAIRS} if extra_domains: print(f"警告:发现多余域名SAN条目:{', '.join(extra_domains)}") # all_valid = False extra_ips = set(ip_addresses) - {pair[1] for pair in REQUIRED_PAIRS} if extra_ips: print(f"警告:发现多余IP SAN条目:{', '.join(extra_ips)}") # all_valid = False return all_valid if __name__ == "__main__": cert = load_certificate("test.crt") dns_list, ip_list = extract_san_entries(cert) if validate_san_pairs(dns_list, ip_list): print("所有预定义的域名-IP配对验证通过") else: print("验证失败")
关键修复点:
- 明确区分SAN中的
DNSName和IPAddress类型条目,避免将IP当作域名处理 - 用
ipaddress模块统一IP地址的字符串格式,避免格式差异导致的误判 - 逐一验证每个配对中的域名和对应IP是否都存在于SAN中
Shell 脚本解决方案
如果偏好Shell处理,以下是基于OpenSSL和awk的验证脚本:
#!/bin/bash # 预定义配对:每行格式为"域名 IP" REQUIRED_PAIRS=$(cat <<EOF sub.example.com 192.168.1.1 test.example.com 10.0.0.1 EOF ) CERT_PATH="test.crt" # 提取SAN条目 SAN_OUTPUT=$(openssl x509 -in "$CERT_PATH" -noout -ext subjectAltName) # 解析DNS名称和IP地址 EXTRACTED_DNS=$(echo "$SAN_OUTPUT" | awk -F',' '{for(i=1;i<=NF;i++){if($i~/DNS:/) print substr($i,5)}}' | sed 's/ //g') EXTRACTED_IPS=$(echo "$SAN_OUTPUT" | awk -F',' '{for(i=1;i<=NF;i++){if($i~/IP Address:/) print substr($i,12)}}' | sed 's/ //g') VALID=0 # 遍历配对验证 echo "$REQUIRED_PAIRS" | while read -r DOMAIN IP; do if ! echo "$EXTRACTED_DNS" | grep -q "^$DOMAIN$"; then echo "错误:域名 $DOMAIN 不在SAN中" VALID=1 fi if ! echo "$EXTRACTED_IPS" | grep -q "^$IP$"; then echo "错误:域名 $DOMAIN 对应的IP $IP 不在SAN中" VALID=1 fi done # 可选:检查多余条目 EXTRA_DNS=$(comm -23 <(echo "$EXTRACTED_DNS" | sort) <(echo "$REQUIRED_PAIRS" | awk '{print $1}' | sort)) if [ -n "$EXTRA_DNS" ]; then echo "警告:多余的域名SAN条目:$EXTRA_DNS" # VALID=1 # 需严格验证时取消注释 fi EXTRA_IPS=$(comm -23 <(echo "$EXTRACTED_IPS" | sort) <(echo "$REQUIRED_PAIRS" | awk '{print $2}' | sort)) if [ -n "$EXTRA_IPS" ]; then echo "警告:多余的IP SAN条目:$EXTRA_IPS" # VALID=1 # 需严格验证时取消注释 fi if [ $VALID -eq 0 ]; then echo "所有配对验证通过" else echo "验证失败" exit 1 fi
使用说明:
- 保存脚本为
validate_san.sh - 赋予执行权限:
chmod +x validate_san.sh - 运行:
./validate_san.sh
内容的提问来源于stack exchange,提问作者Sha
相关产品推荐
相关产品推荐

