You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js/Express:安全校验请求是否来自同域的方法

验证Express接口的同域请求

嘿,这个需求我之前在项目里也碰到过,用req.headers.referer来校验同域请求的思路是可行的,但得先聊聊它的利弊,再给你具体的实现方案,还有更可靠的补充手段~

一、Referer头的优缺点

  • 优势:实现起来特别简单,同域的XMLHttpRequest请求通常会自动带上正确的Referer头(只要用户浏览器没禁用这个字段)
  • 劣势:
    • 部分浏览器会出于隐私设置不发送Referer,或者对其进行修改
    • 一些代理、CDN服务也可能剥离或篡改这个头
    • 非浏览器发起的恶意请求可以轻松伪造Referer(虽然浏览器的同源策略会限制,但爬虫、Postman这类工具可不管这个)

所以这个方法可以作为第一层的快速校验,但绝对不能作为唯一的安全屏障,尤其是涉及敏感数据的接口,必须结合access token验证这类更可靠的手段。

二、具体实现代码

你可以写一个Express中间件来处理这个逻辑:检查请求是否来自允许的同域,是就直接放行;不是的话,就要求对方提供合法的access token。

const express = require('express');
const app = express();

// 定义你的允许的同域域名(比如你的前端页面部署的域名,本地开发和生产环境要分开)
const ALLOWED_ORIGINS = ['http://localhost:3000', 'https://your-production-app.com'];

// 同域校验+token验证中间件
const validateRequestOrigin = (req, res, next) => {
  const referer = req.headers.referer;
  // 判断是否为同域请求:检查Referer是否以允许的域名开头
  const isSameDomain = referer ? ALLOWED_ORIGINS.some(origin => referer.startsWith(origin)) : false;
  
  // 同域请求直接放行
  if (isSameDomain) {
    return next();
  }
  
  // 非同源请求,必须验证access token
  const accessToken = req.headers['authorization']?.split(' ')[1]; // 假设用Bearer Token格式
  if (!accessToken || !verifyAccessToken(accessToken)) { // 替换成你的实际token验证逻辑
    return res.status(401).json({ error: 'Unauthorized: 请提供有效的访问令牌' });
  }
  
  next();
};

// 模拟token验证函数,实际项目里可以用jsonwebtoken这类库实现
const verifyAccessToken = (token) => {
  // 这里写你的校验逻辑:验证签名、过期时间、用户权限等
  return token === 'your-valid-production-token'; // 示例,别直接用这个!
};

// 把中间件应用到所有REST接口路由上
app.use('/api', validateRequestOrigin);

// 示例REST接口
app.get('/api/user/profile', (req, res) => {
  res.json({ username: 'test-user', email: 'test@example.com' });
});

// 服务HTML页面的路由
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/public/index.html');
});

app.listen(3000, () => {
  console.log('服务启动在3000端口啦!');
});

三、更可靠的补充方案

1. 结合CORS配置

Express可以用cors包来精细化控制跨域规则,让浏览器自动拦截非法的跨域请求,再搭配我们的中间件做二次校验:

const cors = require('cors');

const corsOptions = {
  origin: function (origin, callback) {
    // 允许同域请求(origin为null是部分浏览器同域请求的特殊情况),或者你信任的外部域名
    if (!origin || ALLOWED_ORIGINS.includes(origin)) {
      callback(null, true);
    } else {
      // 非允许的origin,浏览器会自动拦截,后续我们的中间件还会做token校验
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true // 允许携带cookie(如果你的同域请求需要的话)
};

// 先应用CORS中间件,再应用我们的校验中间件
app.use('/api', cors(corsOptions), validateRequestOrigin);

2. 使用CSRF令牌(针对同域XHR请求)

如果你的同域请求涉及敏感操作(比如修改数据),用CSRF令牌比Referer头更可靠——因为令牌是服务端生成的,前端页面渲染时注入,XHR请求必须带上这个令牌才能通过校验。可以用csurf包实现:

const csurf = require('csurf');
const cookieParser = require('cookie-parser');

// 先解析cookie,因为csurf需要用cookie存储令牌
app.use(cookieParser());
// 初始化CSRF中间件
const csrfProtection = csurf({ cookie: true });

// 渲染HTML页面时,把CSRF令牌传给前端
app.get('/', csrfProtection, (req, res) => {
  res.send(`
    <html>
      <body>
        <script>
          // 发起XHR请求时,带上CSRF令牌
          const xhr = new XMLHttpRequest();
          xhr.open('POST', '/api/user/update');
          xhr.setRequestHeader('Content-Type', 'application/json');
          xhr.setRequestHeader('X-CSRF-Token', '${req.csrfToken()}');
          xhr.send(JSON.stringify({ username: 'new-name' }));
        </script>
      </body>
    </html>
  `);
});

// 修改我们的中间件,同域请求校验CSRF令牌,非同源请求校验token
const validateRequestOrigin = (req, res, next) => {
  const referer = req.headers.referer;
  const isSameDomain = referer ? ALLOWED_ORIGINS.some(origin => referer.startsWith(origin)) : false;
  
  if (isSameDomain) {
    // 同域请求校验CSRF令牌
    return csrfProtection(req, res, next);
  }
  
  // 非同源请求校验access token
  const accessToken = req.headers['authorization']?.split(' ')[1];
  if (!accessToken || !verifyAccessToken(accessToken)) {
    return res.status(401).json({ error: 'Unauthorized: 无效或缺失访问令牌' });
  }
  
  next();
};

app.use('/api', cors(corsOptions), validateRequestOrigin);

总结

  • Referer头可以作为快速的同域校验手段,但不能单独依赖
  • 结合CORS配置能在浏览器层面拦截大部分非法跨域请求
  • 敏感接口一定要搭配access token验证,同域的敏感操作建议再加CSRF令牌提升安全性

内容的提问来源于stack exchange,提问作者lviggiani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:16:27