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

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

使用说明:

  1. 保存脚本为validate_san.sh
  2. 赋予执行权限:chmod +x validate_san.sh
  3. 运行:./validate_san.sh

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:07:11