nodejs 证书链路诊断

发布于:2025-04-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

以下是 Node.js 证书链路诊断 的完整指南,帮助你排查 HTTPS/TLS 证书相关问题(如 UNABLE_TO_VERIFY_LEAF_SIGNATURECERT_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
  • 解决
    1. 从服务端获取完整的证书链(包含中间证书)。
    2. 在代码中通过 ca 参数加载中间证书:
      const intermediateCert = fs.readFileSync('./path/to/intermediate.crt');
      const agent = new https.Agent({ ca: [intermediateCert] });
      
场景2:自签名证书不受信任
  • 现象DEPTH_ZERO_SELF_SIGNED_CERT
  • 解决
    1. 将自签名证书添加到信任列表:
      # 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
      
    2. 或通过代码加载自签名证书:
      const selfSignedCert = fs.readFileSync('./self-signed.crt');
      const agent = new https.Agent({ ca: [selfSignedCert] });
      
场景3:证书域名不匹配
  • 现象ERR_TLS_CERT_ALTNAME_INVALID
  • 解决
    1. 确保证书的 SAN(Subject Alternative Name)包含请求的域名。
    2. 临时绕过检查(不推荐):
      const agent = new https.Agent({ checkServerIdentity: () => undefined });
      

五、证书管理工具推荐

  1. SSL Labs 测试
    https://www.ssllabs.com/ssltest/
    输入域名,检查证书链配置和安全性评级。

  2. mkcert
    快速生成本地开发用的受信任证书:

    brew install mkcert          # 安装
    mkcert -install              # 生成本地 CA
    mkcert example.com "*.example.com"  # 创建多域名证书
    

六、最佳实践

  1. 生产环境必须启用证书验证,禁用验证会引入中间人攻击风险。
  2. 定期更新证书,使用工具监控证书过期时间(如 Certbot)。
  3. 使用权威 CA 机构证书,避免自签名证书用于生产环境。

通过以上方法,可系统性解决 Node.js 中的证书链路问题。如遇复杂场景,建议结合 Wireshark 抓包分析 TLS 握手过程。