Node.js 安全:XSS、CSRF 防护
直接配置 Node.js 应用拦截恶意脚本与伪造请求。按顺序执行以下步骤即可完成基础防护部署。
阶段一:阻断 XSS(跨站脚本)注入
- 运行 终端命令
npm install express helmet escape-html安装 核心安全依赖库。 - 新建 入口文件
app.js,引入 模块并 初始化 Express 应用实例。 - 挂载
helmet中间件,启用 默认 HTTP 安全响应头拦截规则。const express = require('express'); const helmet = require('helmet'); const { escape } = require('escape-html'); const app = express();
// 注入默认安全头集合
app.use(helmet());
4. **覆盖** 默认内容安全策略。将下方配置追加至中间件链,**限制** 浏览器仅加载同源静态资源。
```javascript
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'"],
imgSrc: ["'self'", "data:"],
connectSrc: ["'self'"]
}
})
);
- 替换 动态数据渲染逻辑。在输出任何用户提交或数据库查询的字段前,调用
escape函数转换特殊字符为 HTML 实体。app.get('/profile', (req, res) => { const safeName = escape(req.query.username); res.send(`欢迎回来,${safeName}`); }); - 发送 测试请求验证拦截效果。在终端执行
curl -I http://localhost:3000/profile,核对 响应头是否包含content-security-policy字段且值未被覆盖为默认放行状态。
阶段二:拦截 CSRF(跨站请求伪造)
- 安装 会话与加密依赖
npm install express-session crypto。 - 创建 会话配置对象,设置 Cookie 的安全传输与生命周期参数。
const session = require('express-session');
app.use(session({
secret: process.env.SESSION_SECRET || 'strong-random-key-here',
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 86400000
}
}));
3. **配置** 关键 Cookie 安全参数。严格对照下表调整会话行为,阻断第三方站点劫持请求。
| 参数名称 | 推荐配置值 | 防护作用 |
| :--- | :--- | :--- |
| `secure` | `true` | 强制仅通过 HTTPS 协议传输,拦截中间人劫持 |
| `httpOnly` | `true` | 禁止前端 JavaScript 读取,阻断 XSS 窃取会话 |
| `sameSite` | `'strict'` | 拦截跨站请求携带,彻底屏蔽第三方站点伪造调用 |
4. **编写** CSRF 令牌生成器。在路由处理前 **生成** 32 字节随机十六进制串,**存入** 当前会话与作用域。
```javascript
const crypto = require('crypto');
function generateCSRFToken(req, res, next) {
if (!req.session.csrfToken) {
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
}
res.locals.csrfToken = req.session.csrfToken;
next();
}
app.use(generateCSRFToken);
- 注入 隐藏字段至所有可提交表单。在 EJS 或 HTML 模板中添加以下代码,确保 每次页面刷新获取新令牌。
<form action="/transfer" method="POST"> <input type="hidden" name="_csrf" value="<%= csrfToken %>"> <input type="number" name="amount" placeholder="转账金额" required> <button type="submit">确认转账</button> </form> - 开发 令牌校验中间件。使用恒定时间比较算法 验证 请求体携带的
_csrf与会话存储值是否完全匹配,失败则立即终止处理。function verifyCSRFToken(req, res, next) { const requestToken = req.body._csrf; const sessionToken = req.session.csrfToken;
if (!requestToken || typeof sessionToken !== 'string' || typeof requestToken !== 'string') {
return res.status(403).json({ error: 'Missing CSRF token' });
}
const reqBuf = Buffer.from(requestToken, 'hex');
const sessBuf = Buffer.from(sessionToken, 'hex');
if (reqBuf.length !== 32 || sessBuf.length !== 32 || !crypto.timingSafeEqual(reqBuf, sessBuf)) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
next();
}
7. **绑定** 校验逻辑至变更类路由。将 `verifyCSRFToken` **放置** 在解析表单中间件之后,目标路由之前。
```javascript
app.use(express.urlencoded({ extended: true }));
app.post('/transfer', verifyCSRFToken, (req, res) => {
res.json({ status: 'success', amount: req.body.amount });
});
阶段三:验证请求链路安全
- 构造 跨站脚本测试载荷。新建
test-xss.html,写入<script>alert('vulnerable')</script>并作为 URL 查询参数提交至受保护路由。 - 观察 浏览器控制台与页面渲染结果。确认控制台未执行任何
alert弹窗,页面仅输出转义后的纯文本节点。 - 核对 伪造请求拦截流程。对照下方时序结构确认各节点拦截逻辑是否生效。graph TD A["浏览器发起 GET 请求"] --> B["服务端返回包含令牌的表单"] B --> C["用户填写并提交 POST 请求"] C --> D{"校验 _csrf 令牌"} D -- "匹配成功" --> E["执行数据写入 返回 200"] D -- "匹配失败" --> F["拒绝请求 返回 403"] G["恶意站点加载伪造页面"] -.->|自动携带 Session Cookie| C C -.->|缺少 _csrf 字段| D
- 执行 依赖漏洞扫描。在终端运行
npm audit,查看 已知安全漏洞清单,并 执行npm audit fix更新受影响的子依赖。 - 配置 自动化安全巡检脚本。将
npm audit加入 CI/CD 流水线,设定exit code非零时自动阻断部署任务。

暂无评论,快来抢沙发吧!