1. Express 安全中间件
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const hpp = require('hpp');
const mongoSanitize = require('express-mongo-sanitize');
const app = express();
// 安全头部
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
},
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }
}));
// CORS
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
// 全局限流
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
max: 100, // 每 IP 100 请求
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => res.status(429).json({ error: 'Too many requests' })
});
app.use('/api/', limiter);
// 严格限流(登录/注册)
const authLimiter = rateLimit({
windowMs: 60 * 60 * 1000,
max: 5,
skipSuccessfulRequests: true
});
app.use('/api/auth/login', authLimiter);
// 参数污染防护
app.use(hpp());
// NoSQL 注入防护
app.use(mongoSanitize());
// 输入大小限制
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
2. JWT 安全实践
const jwt = require('jsonwebtoken');
// 签发(短有效期)
const accessToken = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m', issuer: 'myapp', audience: 'myapp-client' }
);
const refreshToken = jwt.sign(
{ userId: user.id, type: 'refresh' },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
// 验证中间件
function authenticate(req, res, next) {
const auth = req.headers.authorization;
if (!auth?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
try {
const token = auth.substring(7);
req.user = jwt.verify(token, process.env.JWT_SECRET, {
issuer: 'myapp',
audience: 'myapp-client',
clockTolerance: 30 // 30 秒时钟偏差容忍
});
next();
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
}
3. PM2 进程管理
// ecosystem.config.js
module.exports = {
apps: [{
name: 'api-server',
script: './dist/main.js',
instances: 'max', // 使用全部 CPU
exec_mode: 'cluster', // 集群模式
max_memory_restart: '1G', // 内存超限重启
env: { NODE_ENV: 'production' },
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
error_file: './logs/err.log',
out_file: './logs/out.log',
merge_logs: true,
autorestart: true,
kill_timeout: 5000,
listen_timeout: 10000,
// 优雅关闭
wait_ready: true,
shutdown_with_message: true
}]
};
# 部署命令
pm2 start ecosystem.config.js
pm2 reload api-server # 零停机重载
pm2 scale api-server +2 # 扩容
pm2 monit # 监控
4. 生产检查清单
□ 依赖安全:npm audit fix
□ 环境变量:dotenv / 密钥管理系统
□ HTTPS:TLS 1.2+、HSTS
□ 日志:结构化日志(Winston/Pino),不记录敏感信息
□ 监控:PM2 + APM(New Relic / Datadog)
□ 健康检查:/health 端点
□ 优雅关闭:SIGTERM/SIGINT 处理
□ 备份策略:数据库定时备份
□ 灰度发布:蓝绿部署或金丝雀
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。