以下是 Node.js 证书链路诊断 的完整指南,帮助你排查 HTTPS/TLS 证书相关问题(如 UNABLE_TO_VERIFY_LEAF_SIGNATURE
、CERT_HAS_EXPIRED
等错误):
一、常见证书错误类型
错误码 | 原因说明 |
---|---|
UNABLE_TO_VERIFY_LEAF_SIGNATURE |
证书链不完整(缺少中间证书)或根证书未受信任 |
CERT_HAS_EXPIRED |
证书已过期 |
DEPTH_ZERO_SELF_SIGNED_CERT |
自签名证书未被信任 |
ERR_TLS_CERT_ALTNAME_INVALID |
证书的 Subject Alternative Name (SAN) 不匹配请求的域名 |
二、诊断流程与工具
1. 使用 OpenSSL 检查证书链
# 检查远程服务器证书链
openssl s_client -connect <域名>:443 -showcerts
# 输出示例:
# Certificate chain
# 0 s:CN = example.com
# i:C = US, O = Let's Encrypt, CN = R3
# 1 s:C = US, O = Let's Encrypt, CN = R3
# i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
- 关键点:确认证书链完整(服务端证书 → 中间证书 → 根证书)。
2. 验证证书是否受信任
# 查看系统信任的根证书列表(Mac/Linux)
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain > all_certs.pem
# 用 OpenSSL 验证证书链
openssl verify -CAfile all_certs.pem server-cert.pem
3. Node.js 环境变量调试
# 启用详细 TLS 调试日志
export NODE_DEBUG=tls,https
node your-script.js
- 输出会显示证书验证的详细过程,定位失败环节。
三、Node.js 代码层解决方案
1. 忽略证书验证(仅限测试环境!)
const https = require('https');
const agent = new https.Agent({
rejectUnauthorized: false // 关闭证书验证
});
// 在请求中使用 agent
axios.get('https://example.com', { httpsAgent: agent });
2. 手动指定 CA 证书
const fs = require('fs');
const https = require('https');
const caCert = fs.readFileSync('./path/to/ca-cert.pem');
const agent = new https.Agent({
ca: [caCert] // 添加自定义 CA 证书
});
// 使用 agent 发起请求
3. 全局添加根证书(Linux/Node.js)
# 将根证书添加到系统的 CA 存储
sudo cp custom-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# 让 Node.js 使用系统 CA 存储
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
四、常见问题修复
场景1:证书链不完整
- 现象:
UNABLE_TO_VERIFY_LEAF_SIGNATURE
- 解决:
- 从服务端获取完整的证书链(包含中间证书)。
- 在代码中通过
ca
参数加载中间证书:const intermediateCert = fs.readFileSync('./path/to/intermediate.crt'); const agent = new https.Agent({ ca: [intermediateCert] });
场景2:自签名证书不受信任
- 现象:
DEPTH_ZERO_SELF_SIGNED_CERT
- 解决:
- 将自签名证书添加到信任列表:
# Mac sudo security add-trusted-cert -d -k /Library/Keychains/System.keychain self-signed.crt # Linux sudo cp self-signed.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates
- 或通过代码加载自签名证书:
const selfSignedCert = fs.readFileSync('./self-signed.crt'); const agent = new https.Agent({ ca: [selfSignedCert] });
- 将自签名证书添加到信任列表:
场景3:证书域名不匹配
- 现象:
ERR_TLS_CERT_ALTNAME_INVALID
- 解决:
- 确保证书的 SAN(Subject Alternative Name)包含请求的域名。
- 临时绕过检查(不推荐):
const agent = new https.Agent({ checkServerIdentity: () => undefined });
五、证书管理工具推荐
SSL Labs 测试:
https://www.ssllabs.com/ssltest/
输入域名,检查证书链配置和安全性评级。mkcert:
快速生成本地开发用的受信任证书:brew install mkcert # 安装 mkcert -install # 生成本地 CA mkcert example.com "*.example.com" # 创建多域名证书
六、最佳实践
- 生产环境必须启用证书验证,禁用验证会引入中间人攻击风险。
- 定期更新证书,使用工具监控证书过期时间(如 Certbot)。
- 使用权威 CA 机构证书,避免自签名证书用于生产环境。
通过以上方法,可系统性解决 Node.js 中的证书链路问题。如遇复杂场景,建议结合 Wireshark 抓包分析 TLS 握手过程。