Node.js+Express用pem生成自签证书遇CIPHER_MISMATCH问题求助
解决Node.js 10 + Express自签名证书SSL协议/套件不兼容问题
这个问题我之前帮朋友排查过,核心原因是现代浏览器已经全面禁用了老旧的SSL协议(比如SSLv3、TLSv1.0/1.1)和弱加密算法(比如SHA-1),而pem模块默认生成的证书配置、以及Node.js 10的HTTPS服务器默认设置,刚好不符合现代浏览器的安全要求。下面给你两个可行的解决方案:
方案1:调整pem和HTTPS服务器的配置
直接修改你现有的代码,给pem生成证书时指定强算法和必要的证书扩展,同时给HTTPS服务器限定兼容的协议和加密套件:
第一步:修改pem.createCertificate的参数
pem.createCertificate({ days: 365, selfSigned: true, keyBits: 2048, // 至少2048位,推荐4096位增强安全性 hash: 'sha256', // 用SHA-256替代被弃用的SHA-1 // 手动指定证书配置,添加SAN(现代浏览器强制要求)和密钥用途 config: [ '[req]', 'distinguished_name = req_distinguished_name', 'x509_extensions = v3_ca', '[req_distinguished_name]', 'commonName = your-server.local', // 替换成你的内网服务器域名或IP '[v3_ca]', // 添加SAN字段,支持多个IP/域名,比如你的内网IP和localhost 'subjectAltName = IP:192.168.1.100, DNS:your-server.local, DNS:localhost', 'keyUsage = digitalSignature, keyEncipherment', 'extendedKeyUsage = serverAuth' // 指定证书用于服务器认证 ].join('\n') }, this.start);
第二步:修改HTTPS服务器的启动配置
在start方法里,给https.createServer添加明确的SSL协议和加密套件配置:
start(err, keys) { if (err) { throw err } const httpsOptions = { key: keys.serviceKey, cert: keys.certificate, minVersion: 'TLSv1.2', // 只启用现代浏览器支持的TLS 1.2及以上版本 // 指定现代浏览器兼容的强加密套件 ciphers: 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384', honorCipherOrder: true // 优先使用服务器指定的安全套件 }; let server = https.createServer(httpsOptions, app); server.listen(port, () => console.log(`API/NG running on https://192.168.1.100:${port}`) ); }
方案2:直接用OpenSSL命令生成证书(更可靠)
如果pem模块的配置还是有问题,建议直接用系统自带的OpenSSL工具生成证书,再在代码中加载,这种方式更灵活可控:
第一步:在Linux服务器上生成证书
执行以下命令(替换成你的内网IP和域名):
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -days 365 \ -keyout server-key.pem \ -out server-cert.pem \ -subj "/CN=your-server.local" \ -addext "subjectAltName=IP:192.168.1.100, DNS:your-server.local, DNS:localhost"
这个命令会生成私钥server-key.pem和证书server-cert.pem,放在当前目录。
第二步:在代码中加载证书
const fs = require('fs'); const https = require('https'); const express = require('express'); const app = express(); // 配置HTTPS选项 const httpsOptions = { key: fs.readFileSync('./server-key.pem'), cert: fs.readFileSync('./server-cert.pem'), minVersion: 'TLSv1.2', ciphers: 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384', honorCipherOrder: true }; // 启动HTTPS服务器 const server = https.createServer(httpsOptions, app); server.listen(port, () => { console.log(`API/NG running on https://192.168.1.100:${port}`); });
最后补充注意事项
- 信任证书:生成证书后,需要在客户端浏览器(或系统信任存储)中导入
server-cert.pem,否则浏览器会提示"不安全",但不会再出现协议/套件不兼容的错误。 - Node.js版本:Node.js 10已经停止维护了,如果可能的话尽量升级到LTS版本(比如16.x或18.x),新版本的SSL配置更友好,安全性也更高。
- SAN字段:一定要确保证书的SAN字段包含你实际访问的IP或域名,否则浏览器会认为证书不匹配。
内容的提问来源于stack exchange,提问作者monsterAdurm
相关产品推荐
相关产品推荐

