从零到部署:OpenSSL 生成自签名证书与 HTTPS 接口实战

1,339 阅读4分钟

一、自签名证书的核心原理

1. 自签名证书是什么?

  • 定义:开发者自行生成并签发的 SSL 证书(非第三方 CA 签发)。

  • 特点

    • 加密有效:数据通过 TLS 协议加密传输。
    • 浏览器警告:因缺乏可信 CA 验证,需手动信任。

2. 适用场景与风险

  • 适用:本地开发、内网测试、短期验证。

  • 风险

    • 中间人攻击:攻击者伪造证书窃取数据。
    • 信任滥用:用户可能忽略浏览器警告,误信恶意证书。

二、4 步生成自签名证书

步骤 1:生成私钥(Private Key)​

bash
复制
bash
复制
openssl genrsa -out server.key 2048  
  • 参数解释

    • genrsa:生成 RSA 私钥。
    • 2048:密钥长度(低于 2048 位会被视为不安全)。
  • 输出文件server.key(私钥必须严格保密!)。

步骤 2:创建证书签名请求(CSR)​

bash
复制
bash
复制
openssl req -new -key server.key -out server.csr  
  • 交互式填写示例

    plaintext
    复制
    plaintext
    复制
    Country Name (2 letter code) [XX]:CN  
    Common Name (e.g., server FQDN) []:localhost  # 必须与实际访问域名/IP一致!  
    Email Address []:developer@example.com  
    
  • 关键字段Common Name (CN) 必须填写服务域名或 IP(如 localhost192.168.1.100)。

步骤 3:生成自签名证书(CRT)​

bash
复制
bash
复制
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt  
  • 参数解释

    • -days 365:证书有效期(生产环境建议缩短至 90 天)。
    • -signkey:用私钥直接签名,省去 CA 签发流程。

步骤 4:验证证书内容

bash
复制
bash
复制
openssl x509 -in server.crt -text -noout  
  • 检查重点

    • Validity:有效期是否正确。
    • Subject: CN:是否与目标域名/IP 一致。
    • X509v3 Subject Alternative Name:是否包含备用域名/IP(如有)。

三、配置 HTTPS 服务(Nginx/Node.js 双方案)​

方案 1:Nginx 反向代理

nginx
复制
nginx
复制
server {
    listen 443 ssl;
    server_name localhost;

    # 证书路径(绝对路径)
    ssl_certificate     /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;

    # 强制安全协议与加密套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 反向代理到本地 HTTP 服务
    location /api {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
    }
}

# HTTP 强制跳转 HTTPS
server {
    listen 80;
    server_name localhost;
    return 301 https://$host$request_uri;
}
  • 重启 Nginx

    bash
    复制
    bash
    复制
    sudo nginx -s reload  
    

方案 2:Node.js 原生 HTTPS 服务

javascript
复制
javascript
复制
const https = require('https');
const fs = require('fs');
const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt'),
  // 禁用不安全协议
  minVersion: 'TLSv1.2',
  ciphers: 'HIGH:!aNULL:!MD5'
};
https.createServer(options, (req, res) => {
  res.end('HTTPS Success!');
}).listen(443, '0.0.0.0');
  • 启动服务

    bash
    复制
    bash
    复制
    sudo node server.js  # 需 root 权限监听 443 端口
    

四、浏览器信任证书(解决“不安全”警告)​

Chrome 手动信任步骤

  1. 访问 https://localhost → 点击地址栏“不安全”图标 → 导出证书(server.crt)。
  2. 打开 chrome://settings/certificates → 导入证书 → 选择“受信任的根证书颁发机构”。

macOS/Linux 系统级信任

bash
复制
bash
复制
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain server.crt

# Linux (Debian/Ubuntu)
sudo cp server.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

五、高频问题与解决方案

问题 1:ERR_CERT_COMMON_NAME_INVALID

  • 原因:证书的 Common Name 与实际访问域名/IP 不匹配。
  • 解决:重新生成证书,确保 CN 字段正确。

问题 2:SSL_CTX_use_PrivateKey_file error

  • 原因:证书与私钥不匹配或文件路径错误。
  • 解决:检查文件路径,重新生成证书(使用同一私钥)。

问题 3:浏览器缓存旧证书

  • 解决:清除浏览器 SSL 缓存:

    • Chrome:访问 chrome://net-internals/#hsts → 输入域名 → 点击“Delete”。

六、进阶:支持多域名/IP(SAN 扩展)​

生成含 SAN 的证书

bash
复制
markdown
复制
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt \
  -days 365 -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.com"
  • 参数-addext 添加备用名称(支持多个 DNS/IP)。

七、生产环境替代方案

1. Let's Encrypt 免费证书

bash
复制
bash
复制
# 使用 Certbot 自动申请(需域名)
sudo certbot certonly --nginx -d example.com
  • 优势:浏览器自动信任,支持自动续期。

2. 内网私有 CA 搭建

  • 工具easy-rsaOpenSSL CA 命令。
  • 流程:自建根 CA → 签发子证书 → 分发根证书到客户端。

总结

通过本文,你已掌握:

  1. 自签名证书生成:OpenSSL 命令行全流程。
  2. HTTPS 服务配置:Nginx/Node.js 双方案。
  3. 浏览器信任处理:解决“不安全”警告。
  4. 生产环境迁移:Let's Encrypt 或私有 CA 方案。

立即行动

bash
复制
bash
复制
openssl genrsa -out server.key 2048  # 生成你的第一个私钥!