在配置 HTTPS 服务时,你可能遇到过这样的错误:ERR_CERT_COMMON_NAME_INVALID。这个错误通常与证书的 Subject Alternative Name(SAN) 扩展有关。本文详细介绍 SAN 扩展的原理、作用以及 OpenSSL 命令行实战技巧。
为什么需要 SAN 扩展?#
在早期 X.509 证书中,域名信息只存储在 Subject(主体) 字段的 Common Name(CN)中。然而,这种方式存在几个问题:
- CN 只能包含一个域名:无法在单张证书中覆盖多个域名
- 国际化域名(IDN)支持有限:中文域名等特殊字符处理复杂
- 不符合现代 PKI 标准:RFC 5280 已不推荐使用 CN 作为域名验证依据
SAN 扩展解决了这些问题,允许证书包含多个域名、IP 地址甚至电子邮件地址。
SAN 支持的类型#
SAN 扩展支持以下类型的备用名称:
| 类型 |
说明 |
示例 |
| DNS |
域名 |
example.com, *.example.com |
| IP |
IP 地址 |
192.168.1.1, 10.0.0.1 |
| email |
电子邮件 |
admin@example.com |
| URI |
统一资源标识符 |
https://example.com/path |
| RID |
注册标识符 |
oid:1.2.3.4.5 |
⚠️ 重要:现代浏览器和客户端主要支持 DNS 和 IP 类型,其他类型使用较少。
OpenSSL 命令行实战#
1. 创建带 SAN 的配置文件#
首先创建一个配置文件,定义 SAN 扩展:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
cat > san.cnf << 'EOF'
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
encrypt_key = no
[req_distinguished_name]
C = CN
ST = Shanghai
O = Example Inc
CN = example.com
[v3_req]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = *.example.com
IP.1 = 192.168.1.1
IP.2 = 10.0.0.1
email.1 = admin@example.com
EOF
|
关键配置说明:
subjectAltName = @alt_names:引用 [alt_names] 小节中定义的备用名称
DNS.x:DNS 域名条目
IP.x:IP 地址条目(支持 IPv4 和 IPv6)
email.x:电子邮件地址(注意使用小写 email)
2. 生成密钥和证书签名请求(CSR)#
1
2
3
4
5
|
# 生成私钥
openssl genrsa -out san-key.pem 2048
# 生成 CSR
openssl req -new -key san-key.pem -out san.csr -config san.cnf
|
3. 自签名生成证书#
1
2
3
|
openssl x509 -req -in san.csr -signkey san-key.pem \
-out san.pem -days 365 \
-extfile san.cnf -extensions v3_req
|
4. 验证 SAN 扩展#
1
2
3
4
5
|
# 详细查看
openssl x509 -in san.pem -noout -text | grep -A 10 "Subject Alternative Name"
# 简短查看
openssl x509 -in san.pem -noout -ext subjectAltName
|
输出示例:
1
2
|
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com, DNS:*.example.com, IP Address:192.168.1.1, IP Address:10.0.0.1, email:admin@example.com
|
5. 使用 OpenSSL s_client 测试#
使用新证书测试 HTTPS 连接:
1
2
3
4
|
openssl s_client -connect example.com:443 \
-servername example.com \
-showcerts </dev/null 2>/dev/null | \
openssl x509 -noout -ext subjectAltName
|
通配符证书#
通配符证书使用 *.example.com 格式,可以匹配所有子域名:
1
2
3
|
[alt_names]
DNS.1 = example.com
DNS.2 = *.example.com
|
这将覆盖:
- ✅
www.example.com
- ✅
api.example.com
- ✅
mail.example.com
- ❌
example.com(除非显式列出)
- ❌
sub.www.example.com(不匹配双通配符)
多域名证书(SAN 证书)#
一张证书可以包含任意数量的域名,无需为每个域名购买单独证书:
1
2
3
4
5
6
|
[alt_names]
DNS.1 = example.com
DNS.2 = example.org
DNS.3 = example.net
DNS.4 = www.example.com
DNS.5 = m.example.com
|
使用 acme.sh 自动管理 SAN 证书#
如果你使用 acme.sh 管理证书,可以通过以下方式指定 SAN:
1
2
3
4
5
6
|
# 添加多个域名
acme.sh --issue -d example.com -d www.example.com -d api.example.com \
--dns dns_cf
# 查看已签发证书的 SAN
acme.sh --info -c /path/to/cert.cer | grep -A 5 "Subject Alternative Name"
|
常见问题#
1. 浏览器显示 “ERR_CERT_COMMON_NAME_INVALID”#
原因:证书的 SAN 扩展中不包含请求的域名。
解决方案:重新签发证书,确保在 SAN 中包含所有需要绑定的域名。
2. IP 地址作为 SAN#
1
2
3
4
|
[alt_names]
IP.1 = 192.168.1.100
IP.2 = 10.0.0.1
IPv6.1 = ::1
|
⚠️ 注意:某些浏览器对 IP 类型的 SAN 有特殊要求,例如需要使用 IP.1 而非 IPv6.1。
3. 只保留 SAN 而忽略 CN#
现代浏览器优先检查 SAN 扩展,CN 字段仅作为后备。配置建议:
1
2
3
4
5
6
7
|
# CN 可以设置为第一个域名或公司名
CN = example.com
# 所有需要绑定的域名列在 SAN 中
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
|
安全最佳实践#
- 列出所有需要的域名:签发前仔细规划,避免后续重新签发
- 包含根域名:如需
example.com 和 www.example.com,两个都要列出
- 避免过多域名:单张证书域名过多会增加管理复杂度,考虑使用多张证书
- 定期检查过期时间:使用监控工具跟踪证书到期
- 使用可信 CA:选择受浏览器信任的证书颁发机构
SAN 扩展是现代 X.509 证书的核心组件:
- 支持多域名、单证书覆盖多个服务
- 通配符证书简化子域名管理
- 符合 RFC 5280 和浏览器安全要求
- OpenSSL 命令行操作简单直观
正确配置 SAN 扩展可以避免浏览器安全警告,确保 HTTPS 服务稳定运行。
参考来源