保护 Node.js API:真正有效的模式
速率限制、Zod 校验、蜜罐与安全头——从公开表单到你的收件箱之间的每一层防护。
构建安全的 Node.js API 需要的不仅是认证中间件和 HTTPS。生产 API 面临不断演化的自动化攻击、畸形 payload 和滥用模式。本指南涵盖速率限制、输入验证、蜜罐和 Content Security Policy 头等实用安全模式,你今天即可实施以加固后端,同时不牺牲开发速度或用户体验。
速率限制策略
速率限制是抵御暴力攻击、凭据填充和资源耗尽的第一道防线。没有它,单个恶意客户端可压垮数据库、推高云成本或拒绝合法用户服务。
在多个层级实施速率限制以获得全面保护:
- 全局限速 — 限制每个 IP 在所有端点的总请求数以防止容量攻击。
- 端点特定限制 — 对认证、密码重置和支付端点应用更严格限制。
- 基于用户的限制 — 认证后按用户 ID 限速以防止账户级滥用。
- 滑动窗口算法 — 优先滑动窗口而非固定窗口,防止窗口边界处的突发攻击。
import rateLimit from "express-rate-limit";
import RedisStore from "rate-limit-redis";
import { createClient } from "redis";
const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
const globalLimiter = rateLimit({
store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
message: { error: "Too many requests, please try again later." },
});
const authLimiter = rateLimit({
store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
windowMs: 15 * 60 * 1000,
max: 5,
message: { error: "Too many login attempts." },
});
app.use("/api/", globalLimiter);
app.use("/api/auth/login", authLimiter);
在多实例部署中使用 Redis 作为限速计数器后端。内存 store 在服务器重启时重置,且在负载均衡实例间不共享状态,在滚动部署期间留下攻击者可利用的空隙。
输入验证与净化
永远不要信任客户端输入。每个请求体、查询参数和头值在验证前都可能是恶意的。Zod 或 Joi 等基于模式的验证库提供类型安全解析,在畸形数据到达业务逻辑或数据库查询之前拒绝它们。
使用 Zod 进行模式验证
为每个端点定义严格模式,并在路由处理程序边界验证传入数据。对验证失败的请求返回描述性 400 响应,而非允许部分或损坏的数据传播。
import { z } from "zod";
const createUserSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(100).trim(),
age: z.number().int().min(13).max(120).optional(),
role: z.enum(["user", "admin"]).default("user"),
});
app.post("/api/users", async (req, res) => {
const result = createUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: "Validation failed",
details: result.error.flatten().fieldErrors,
});
}
const user = await userService.create(result.data);
res.status(201).json(user);
});
除模式验证外,净化字符串输入以防止 NoSQL 注入、存储内容中的 XSS 和文件上传端点中的路径遍历。参数化查询和 ORM 方法可防止 SQL 注入,但 NoSQL 数据库需要同等警惕 — 切勿将原始用户对象直接传入 MongoDB 查询操作符。
用于机器人检测的蜜罐字段
蜜罐是合法用户永远看不到或填写的隐藏表单字段,但自动化机器人通常会填充。当蜜罐字段有值时,你可静默拒绝提交,不向机器人操作者透露检测机制。
在面向公众的表单上实施蜜罐 — 联系表单、注册页和评论提交:
- 添加名为
website_url或fax_number的文本输入字段。 - 用 CSS 将其定位到屏幕外隐藏,而非
display: none(复杂机器人可检测)。 - 添加
tabindex="-1"和autocomplete="off"以防止意外聚焦。 - 在服务器端,拒绝蜜罐字段非空的任何提交。
- 包含时间戳字段,拒绝两秒内完成的提交。
// Server-side honeypot check
app.post("/api/contact", (req, res) => {
const { honeypot, submittedAt, ...validFields } = req.body;
if (honeypot) {
// Silently accept to avoid tipping off the bot
return res.status(200).json({ success: true });
}
const elapsed = Date.now() - submittedAt;
if (elapsed < 2000) {
return res.status(200).json({ success: true });
}
// Process legitimate submission
processContactForm(validFields);
res.status(200).json({ success: true });
});
蜜罐不能替代 CAPTCHA 或速率限制,但能以零用户摩擦消除大量不成熟的机器人流量。
Content Security Policy 头
Content Security Policy 是 HTTP 响应头,指示浏览器允许加载哪些资源。对于提供 HTML 响应的 API — 管理仪表板、文档站点或 SSR 页面 — CSP 通过阻止内联脚本和未授权外部资源防止 XSS 攻击。
使用 Express 应用的标准安全中间件 Helmet 配置 CSP:
import helmet from "helmet";
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.example.com"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
})
);
即使对于仅 JSON 的 API,也设置以下互补安全头:
- Strict-Transport-Security — 强制所有未来请求使用 HTTPS。
- X-Content-Type-Options: nosniff — 防止 MIME 类型嗅探攻击。
- X-Frame-Options: DENY — 通过 iframe 嵌入阻止点击劫持。
- Referrer-Policy: strict-origin-when-cross-origin — 限制 referrer 信息泄露。
- Permissions-Policy — 禁用不必要的浏览器功能如摄像头和地理位置。
认证与授权模式
速率限制和验证保护外围,但认证和授权保护单个资源。遵循以下成熟模式为服务现代前端应用的 Node.js API。
- 将 JWT 存储在 httpOnly、secure、SameSite cookie 中 — 切勿放在 XSS 可窃取的 localStorage。
- 实施带重用检测的刷新令牌轮换,以限制令牌被盗的影响范围。
- 在路由级别应用基于角色的访问控制,而非仅在 UI 级别。
- 在每个受保护请求上验证 JWT 签名和过期 — 不要仅信任解码后的 payload。
- 记录认证失败及 IP 地址和用户代理以供取证分析。
安全监控与事件响应
安全模式只有与可观测性结合才有效。将限速违规、验证失败和蜜罐触发记录到集中日志平台。对异常模式设置告警 — 401 响应突然激增可能表示凭据填充活动,400 错误增加可能表示模糊测试探测漏洞。
定期审查 API 表面安全。OWASP ZAP 和 npm audit 等自动化工具可捕获已知漏洞,但授权逻辑、文件上传处理和第三方集成点的人工审查仍然必要。安全不是一次交付的功能 — 它是随应用和威胁态势演进的持续实践。