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

如何让Node.js+Express应用的API仅接受自身页面的AJAX请求?

实现Express API仅接受自站页面AJAX请求的最佳方案

要实现API仅允许自站页面发起的AJAX请求调用,核心是利用浏览器的同源策略结合令牌验证,单纯检查Origin头不可靠(易伪造),以下是可行的方案:

一、CSRF令牌验证(最佳方案)

这是目前最可靠的方式,通过绑定会话与请求令牌,确保请求来自自站渲染的页面:

实现步骤:

  1. 配置Session存储用户会话信息,用于保存CSRF令牌
  2. 渲染页面时生成CSRF令牌,注入到页面的JS中
  3. AJAX请求时携带该令牌,API接口验证令牌与Session中存储的是否匹配

代码示例(使用csurf中间件):

首先安装依赖:

npm install csurf express-session

Express配置代码:

const express = require('express');
const session = require('express-session');
const csrf = require('csurf');
const app = express();

// 配置Session,生产环境建议替换为Redis等持久化存储
app.use(session({
  secret: 'your-strong-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: { 
    secure: process.env.NODE_ENV === 'production', // 生产环境开启HTTPS时启用
    httpOnly: true
  }
}));

// 初始化CSRF中间件,令牌存储在Session中
const csrfProtection = csrf({ cookie: false });

// 渲染页面时注入CSRF令牌
app.get('/homepage', csrfProtection, (req, res) => {
  res.send(`
    <html>
      <body>
        <input type="text" id="userInput">
        <button onclick="submitRequest()">提交</button>
        <script>
          async function submitRequest() {
            const inputVal = document.getElementById('userInput').value;
            const response = await fetch('/api/getinfo', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'X-CSRF-Token': '${req.csrfToken()}'
              },
              body: JSON.stringify({ input: inputVal })
            });
            const data = await response.json();
            console.log(data);
          }
        </script>
      </body>
    </html>
  `);
});

// API接口验证CSRF令牌
app.post('/api/getinfo', csrfProtection, express.json(), (req, res) => {
  res.json({ 
    status: 'success',
    message: '请求来自自站页面',
    input: req.body.input
  });
});

app.listen(3000, () => console.log('服务运行在3000端口'));

原理:

  • 浏览器访问/homepage时,服务器生成唯一CSRF令牌并绑定到当前Session
  • 页面中的AJAX请求会自动携带同域Session Cookie,同时在请求头中带上令牌
  • API接口验证请求头的令牌与Session中的令牌是否一致,不一致则拒绝请求
  • 直接通过Postman等工具调用API时,无法获取有效Session和匹配的令牌,无法通过验证

二、辅助验证:检查Referer头

虽然Referer头也可被伪造,但对于普通场景能增加一层防护,建议与CSRF令牌结合使用:

// 给API路由添加Referer检查中间件
app.use('/api', (req, res, next) => {
  const referer = req.get('Referer');
  const allowedHost = `${req.protocol}://${req.get('host')}`;
  // 验证Referer是否来自自站
  if (referer?.startsWith(allowedHost)) {
    next();
  } else {
    res.status(403).json({ error: '禁止直接访问API' });
  }
});

注意:部分浏览器在HTTPS转HTTP、隐私模式下可能不发送Referer头,因此不能单独依赖此方法。

为什么Origin头不可靠?

Origin头可通过工具(如Postman)手动设置为目标域名,完全无法阻止伪造请求,因此单独使用Origin检查没有实际防护作用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:24:44