HTTPS与TLS配置
HTTPS 通过 TLS/SSL 加密传输数据,保护用户隐私和数据完整性。
TLS 基础概念
握手流程
JavaScript
客户端 服务器
| |
|-------- Client Hello ---------------> | (支持的加密套件)
| |
|<------- Server Hello --------------- | (选定的加密套件)
|<------- Certificate ----------------- | (服务器证书)
|<------- Server Hello Done ---------- |
| |
|-------- Client Key Exchange --------> | (预主密钥)
|-------- Change Cipher Spec ---------> |
|-------- Finished -------------------> |
| |
|<------- Change Cipher Spec ---------- |
|<------- Finished ------------------- |
| |
|======== 加密通信 ===================> |
证书类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
| DV | 域名验证,快速签发 | 个人站点、开发测试 |
| OV | 组织验证,显示公司名 | 企业网站 |
| EV | 扩展验证,最高信任 | 金融、电商 |
Node.js HTTPS 服务
基本配置
JavaScript
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
ca: fs.readFileSync('ca-bundle.pem') // 可选:中间证书
};
const server = https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello HTTPS');
});
server.listen(443, () => {
console.log('HTTPS server running on port 443');
});
Express HTTPS 配置
JavaScript
const express = require('express');
const https = require('https');
const fs = require('fs');
const app = express();
// HTTPS 服务器
const options = {
key: fs.readFileSync('./certs/private.key'),
cert: fs.readFileSync('./certs/certificate.crt'),
ca: fs.readFileSync('./certs/ca_bundle.crt')
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS server running on port 443');
});
// HTTP 重定向到 HTTPS
const http = require('http');
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
使用 helmet 增强安全
JavaScript
const helmet = require('helmet');
app.use(helmet());
// HSTS - 强制 HTTPS
app.use(helmet.hsts({
maxAge: 31536000, // 1年
includeSubDomains: true, // 包含子域名
preload: true // 预加载到浏览器
}));
// 禁用不安全功能
app.use(helmet.frameguard({ action: 'deny' }));
app.use(helmet.noSniff());
app.use(helmet.xssFilter());
TLS 版本与加密套件
禁用不安全版本
JavaScript
const tls = require('tls');
// 创建安全上下文
const secureContext = tls.createSecureContext({
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
// 禁用 SSLv2, SSLv3, TLSv1, TLSv1.1
secureOptions: tls.constants.SSL_OP_NO_SSLv2 |
tls.constants.SSL_OP_NO_SSLv3 |
tls.constants.SSL_OP_NO_TLSv1 |
tls.constants.SSL_OP_NO_TLSv1_1
});
// 推荐配置
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
minVersion: 'TLSv1.2', // 最低版本
maxVersion: 'TLSv1.3', // 最高版本
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-GCM-SHA256'
].join(':'),
honorCipherOrder: true
};
推荐加密套件
Bash
const RECOMMENDED_CIPHERS = [
// TLS 1.3
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',
// TLS 1.2
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-CHACHA20-POLY1305'
].join(':');
证书获取与管理
Let's Encrypt 免费证书
JavaScript
# 使用 certbot
sudo apt install certbot
sudo certbot certonly --standalone -d example.com -d www.example.com
# 自动续期
sudo certbot renew --dry-run
# 定时任务
0 0 1 * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
Node.js 自动续期
nginx
const Greenlock = require('greenlock');
const greenlock = Greenlock.create({
packageRoot: __dirname,
configDir: './greenlock.d',
maintainerEmail: 'admin@example.com'
});
// 自动管理证书
greenlock.manager.defaults({
subscriberEmail: 'admin@example.com',
agreeToTerms: true
}).then(() => {
return greenlock.add({
subject: 'example.com',
altnames: ['example.com', 'www.example.com']
});
});
证书文件说明
JavaScript
private.key # 私钥(保密)
certificate.crt # 服务器证书
ca_bundle.crt # 中间证书链
fullchain.crt # 完整证书链(证书+中间证书)
反向代理配置
Nginx HTTPS 配置
Bash
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# HTTP 重定向
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
Express 信任代理
Bash
// 信任反向代理
app.set('trust proxy', 1);
// 获取真实 IP
app.use((req, res, next) => {
const ip = req.ip || req.headers['x-forwarded-for'];
const protocol = req.protocol; // 正确获取 https
next();
});
安全配置检测
SSL Labs 测试
JavaScript
# 访问 https://www.ssllabs.com/ssltest/
# 目标:A+ 评级
命令行检测
JavaScript
# 检查 TLS 版本
openssl s_client -connect example.com:443 -tls1_2
# 检查证书信息
openssl x509 -in certificate.pem -text -noout
# 检查加密套件
nmap --script ssl-enum-ciphers -p 443 example.com
# 使用 testssl.sh
git clone https://github.com/drwetter/testssl.sh.git
./testssl.sh example.com
Node.js 检测脚本
Bash
const tls = require('tls');
function checkTLSConfig(hostname) {
const socket = tls.connect(443, hostname, {
servername: hostname,
rejectUnauthorized: false
}, () => {
console.log('TLS Version:', socket.getProtocol());
console.log('Cipher:', socket.getCipher());
console.log('Certificate:', socket.getPeerCertificate().subject);
socket.end();
});
socket.on('error', (err) => {
console.error('TLS Error:', err.message);
});
}
checkTLSConfig('example.com');
常见问题与解决
混合内容问题
text
// 强制 HTTPS 重定向
app.use((req, res, next) => {
if (req.protocol === 'http') {
return res.redirect(301, `https://${req.headers.host}${req.url}`);
}
next();
});
// 设置 HSTS 头
app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
证书链不完整
text
# 合并证书链
cat certificate.crt ca_bundle.crt > fullchain.crt
# 验证证书链
openssl verify -CAfile ca_bundle.crt certificate.crt
注意:生产环境建议使用 Nginx/Caddy 等 Web 服务器处理 TLS,Node.js 应用监听本地端口。
要点总结
- 使用 TLS 1.2+ 版本,禁用 SSLv3、TLSv1、TLSv1.1
- 配置强加密套件,优先使用 ECDHE 和 AES-GCM
- 启用 HSTS 强制 HTTPS,配置 maxAge 和 includeSubDomains
- 使用 Let's Encrypt 免费证书,配置自动续期
- 使用 SSL Labs 定期检测 HTTPS 配置安全性
📝 发现内容有误?点击此处直接编辑