Node.js多层架构下验证请求来源:确保请求来自自有前端的方案
验证请求来自自有前端的解决方案
针对你这种三层架构下中间层Node.js服务器需要验证请求来源的问题,我整理了几个实用且成熟的方案,结合你的场景给出具体实现思路:
1. Origin/Referer 请求头校验
这是最基础的防御手段,利用浏览器的同源策略特性:
- 原理:浏览器发送跨域请求时会自动带上
Origin头(简单请求)或Referer头(跳转/部分请求),标识请求的发起页面域名。 - 实现步骤:
- 在Node.js中间层中,检查请求的
Origin或Referer是否属于你的前端域名白名单(比如https://your-frontend.com,开发环境可加入本地调试地址)。 - 示例代码(Express框架):
const allowedOrigins = ['https://your-frontend.com', 'http://localhost:3000']; app.use((req, res, next) => { // 优先取Origin,没有则从Referer中解析域名 const origin = req.headers.origin || (req.headers.referer ? `${req.headers.referer.split('/')[0]}//${req.headers.referer.split('/')[2]}` : ''); if (allowedOrigins.includes(origin)) { next(); } else { res.status(403).send('Forbidden: Invalid request origin'); } });
- 在Node.js中间层中,检查请求的
- 注意:这种方式容易被手动伪造请求头,所以不能单独作为唯一防御手段,需要配合其他方案。
2. CSRF Token 验证
适合表单提交类请求,是Web应用防御跨站请求伪造的标准方案:
- 原理:前端页面加载时从中间层获取唯一CSRF Token,提交请求时将Token放在请求头或表单隐藏字段中,中间层校验Token与用户Session中的值是否一致。
- 实现步骤:
- 前端加载页面时,向中间层请求CSRF Token(比如
GET /api/csrf-token),中间层生成Token并存储在用户Session中(需设置HttpOnly: false让前端能读取)。 - 前端提交表单/XHR请求时,将Token放在
X-CSRF-Token请求头中。 - 中间层校验请求头中的Token与Session中的Token是否匹配。
- 前端加载页面时,向中间层请求CSRF Token(比如
- 示例代码(Express + express-session):
const crypto = require('crypto'); // 生成CSRF Token接口 app.get('/api/csrf-token', (req, res) => { req.session.csrfToken = crypto.randomBytes(16).toString('hex'); res.send({ csrfToken: req.session.csrfToken }); }); // CSRF校验中间件 app.use((req, res, next) => { // 仅对修改类请求校验 if (['POST', 'PUT', 'DELETE'].includes(req.method)) { const requestCsrfToken = req.headers['x-csrf-token']; if (requestCsrfToken === req.session.csrfToken) { next(); } else { res.status(403).send('Forbidden: Invalid CSRF Token'); } } else { next(); } }); - 优势:Token与用户Session绑定,伪造难度大,完美适配你的表单提交场景。
3. 请求签名验证
适合更严格的场景,即使请求头被伪造也能有效验证:
- 原理:前端和中间层共享一个保密密钥,前端发送请求时,用密钥对请求关键参数(请求路径、时间戳、用户ID等)进行哈希签名,中间层用相同规则验证签名有效性。
- 实现步骤:
- 前端通过安全接口动态获取共享密钥(禁止硬编码在前端代码中,密钥需定期轮换)。
- 发送请求时,生成签名:将
请求路径 + 时间戳 + 用户ID拼接后,用HMAC-SHA256算法和密钥生成签名,把签名和时间戳放在X-Signature、X-Timestamp请求头中。 - 中间层先校验时间戳是否在有效范围(比如5分钟内,防止重放攻击),再生成预期签名与请求头中的签名对比。
- 示例代码(Node.js中间层):
const crypto = require('crypto'); const sharedSecret = 'your-rotating-shared-secret'; // 与前端共享的密钥,注意保密和定期轮换 app.use((req, res, next) => { const signature = req.headers['x-signature']; const timestamp = req.headers['x-timestamp']; const path = req.path; const userId = req.session.userId; // 结合用户登录态提升安全性 // 校验请求是否过期 if (Date.now() - parseInt(timestamp) > 5 * 60 * 1000) { return res.status(403).send('Forbidden: Request expired'); } // 生成预期签名 const payload = `${path}${timestamp}${userId}`; const expectedSignature = crypto.createHmac('sha256', sharedSecret) .update(payload) .digest('hex'); if (signature === expectedSignature) { next(); } else { res.status(403).send('Forbidden: Invalid request signature'); } });
综合建议
- 对于你的表单提交场景,优先使用CSRF Token + Origin校验的组合,简单易实现且安全性足够。
- 如果需要更高的安全等级,再加入请求签名验证,防止请求被重放或伪造。
- 永远不要依赖单一防御手段,多层验证能大幅提升系统安全性。
内容的提问来源于stack exchange,提问作者Abdol Seed
相关产品推荐
相关产品推荐

