在配置 HTTPS 服务时,你可能遇到过这样的错误:ERR_CERT_COMMON_NAME_INVALID。这个错误通常与证书的 Subject Alternative Name(SAN) 扩展有关。本文详细介绍 SAN 扩展的原理、作用以及 OpenSSL 命令行实战技巧。

为什么需要 SAN 扩展?

在早期 X.509 证书中,域名信息只存储在 Subject(主体) 字段的 Common Name(CN)中。然而,这种方式存在几个问题:

  1. CN 只能包含一个域名:无法在单张证书中覆盖多个域名
  2. 国际化域名(IDN)支持有限:中文域名等特殊字符处理复杂
  3. 不符合现代 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

安全最佳实践

  1. 列出所有需要的域名:签发前仔细规划,避免后续重新签发
  2. 包含根域名:如需 example.comwww.example.com,两个都要列出
  3. 避免过多域名:单张证书域名过多会增加管理复杂度,考虑使用多张证书
  4. 定期检查过期时间:使用监控工具跟踪证书到期
  5. 使用可信 CA:选择受浏览器信任的证书颁发机构

总结

SAN 扩展是现代 X.509 证书的核心组件:

  • 支持多域名、单证书覆盖多个服务
  • 通配符证书简化子域名管理
  • 符合 RFC 5280 和浏览器安全要求
  • OpenSSL 命令行操作简单直观

正确配置 SAN 扩展可以避免浏览器安全警告,确保 HTTPS 服务稳定运行。


参考来源