证书指纹(Certificate Fingerprint,也称 Thumbprint)是证书的唯一标识符。通过对证书内容进行哈希计算得出,广泛应用于证书 pinning、自动化监控、证书比对等场景。本文详细介绍 OpenSSL 计算证书指纹的各种方法。
什么是证书指纹?#
证书指纹是对整个证书 DER 编码内容进行哈希计算的结果。常见哈希算法:
- SHA-1:兼容性较好,但因安全原因已不推荐
- SHA-256:目前推荐的主要算法
- MD5:仅用于兼容旧系统,强烈不推荐
基本计算方法#
使用 x509 命令#
1
2
3
4
5
6
7
8
|
# SHA-256 指纹(推荐)
openssl x509 -noout -fingerprint -sha256 -in certificate.crt
# SHA-1 指纹
openssl x509 -noout -fingerprint -sha1 -in certificate.crt
# MD5 指纹(不推荐)
openssl x509 -noout -fingerprint -md5 -in certificate.crt
|
实际输出示例:
1
|
sha256 Fingerprint=71:DA:A0:3E:9E:A4:A8:C3:B0:D8:E9:2B:FD:EB:81:77:71:39:82:93:3E:C6:E1:21:7A:C1:DC:C0:D1:C0:78:F2
|
使用 dgst 命令#
1
2
|
# 使用 dgst 计算 SHA-256 指纹
openssl dgst -sha256 certificate.crt
|
输出:
1
|
SHA256(certificate.crt)= bf2b929d1ba24ae694726ea760a3c2a9faeedb9d38ee5c68b0c6f11c5e2256d5
|
注意:dgst 命令直接对 PEM 文件内容计算哈希,与 x509 -fingerprint 的计算方式略有不同。前者包含 PEM 头部和尾部,后者仅对证书 DER 编码计算。
提取指纹值的技巧#
去除指纹前缀#
在脚本中需要提取纯指纹值(去掉 sha256 Fingerprint= 前缀):
1
2
3
|
# 使用 sed 提取
FINGERPRINT=$(openssl x509 -noout -fingerprint -sha256 -in certificate.crt | sed 's/.*=//')
echo $FINGERPRINT
|
批量计算多个证书指纹#
1
2
3
4
|
# 遍历目录下所有证书
for cert in *.crt; do
echo "$cert: $(openssl x509 -noout -fingerprint -sha256 -in "$cert" | sed 's/.*=//')"
done
|
证书比对实战#
判断两个证书是否相同#
1
2
3
4
5
6
7
8
9
|
# 提取两个证书的指纹并比较
CERT1_FP=$(openssl x509 -noout -fingerprint -sha256 -in cert1.crt | sed 's/.*=//')
CERT2_FP=$(openssl x509 -noout -fingerprint -sha256 -in cert2.crt | sed 's/.*=//')
if [ "$CERT1_FP" = "$CERT2_FP" ]; then
echo "两个证书相同"
else
echo "证书不同"
fi
|
验证证书是否匹配私钥#
通过比较证书和私钥的公钥指纹来验证匹配性:
1
2
3
4
5
6
7
8
|
# 提取证书中的公钥指纹
CERT_PUBKEY_FP=$(openssl x509 -in certificate.crt -pubkey -noout | openssl dgst -sha256)
# 提取私钥中的公钥指纹
KEY_PUBKEY_FP=$(openssl pkey -in private.key -pubout -outform DER | openssl dgst -sha256)
echo "证书公钥指纹: $CERT_PUBKEY_FP"
echo "私钥公钥指纹: $KEY_PUBKEY_FP"
|
SPKI 指纹:公钥独立标识#
SPKI(Subject Public Key Info)指纹仅基于公钥计算,不受证书有效期、签名算法等因素影响。适合用于公钥固定场景:
1
2
|
# 计算 SPKI 指纹
openssl x509 -in certificate.crt -pubkey -noout | openssl dgst -sha256
|
输出:
1
|
SHA2-256(stdin)= 654875f2bccf6a00beaca4e4a464422118a564032d372ebbc79fd06ff05a1340
|
常见应用场景#
1. 证书 Pinning#
在应用代码中硬编码证书指纹,验证服务器证书是否可信:
1
2
|
// JavaScript 示例
const expectedFingerprint = "71:DA:A0:3E:9E:A4:A8:C3:B0:D8:E9:2B:FD:EB:81:77:71:39:82:93:3E:C6:E1:21:7A:C1:DC:C0:D1:C0:78:F2";
|
2. 证书过期监控#
在监控脚本中记录指纹以便精确识别证书:
1
2
3
4
5
6
7
8
9
|
#!/bin/bash
# 监控证书变化
CURRENT_FP=$(openssl x509 -noout -fingerprint -sha256 -in /etc/ssl/certs/server.crt | sed 's/.*=//')
SAVED_FP=$(cat /var/lib/cert-fingerprint.txt 2>/dev/null)
if [ "$CURRENT_FP" != "$SAVED_FP" ]; then
echo "证书已更新!新指纹: $CURRENT_FP" | mail -s "证书变更告警" admin@example.com
echo "$CURRENT_FP" > /var/lib/cert-fingerprint.txt
fi
|
3. 自动化部署校验#
部署前验证证书链中各证书的指纹:
1
2
3
4
5
|
# 验证证书链未被篡改
EXPECTED_ROOT_FP="AA:BB:CC:DD:..."
ACTUAL_ROOT_FP=$(openssl x509 -noout -fingerprint -sha256 -in root-ca.crt | sed 's/.*=//')
[ "$EXPECTED_ROOT_FP" = "$ACTUAL_ROOT_FP" ] || { echo "根证书不匹配!"; exit 1; }
|
各算法指纹对比#
| 算法 |
用途 |
安全性 |
兼容性 |
| SHA-256 |
证书指纹、Pinning |
高 |
优秀 |
| SHA-1 |
旧系统兼容 |
中 |
优秀 |
| MD5 |
遗留系统 |
低 |
良好 |
注意事项#
- 指纹不是证书唯一标识:证书重新签发后指纹会变化
- 公钥指纹更稳定:更换证书但保留相同公钥时,SPKI 指纹不变
- 注意格式:指纹通常使用冒号分隔的十六进制字符串
- 存储安全:在配置文件中存储指纹时注意访问权限
参考来源#