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

如何为前后端分离架构下的Node.js REST API公开GET接口做安全防护?

针对公开GET API防爬的解决方案(适配你的Node/Express + Next.js架构)

嘿,结合你的技术栈和需求,咱们来梳理下如何保护那些无需登录但不想被第三方爬取的GET API端点。首先明确:Helmet主要是帮你设置安全HTTP头(比如防XSS、点击劫持),加固基础安全,但它没法直接防止API被爬取,得搭配其他手段才行。下面是从易到难的最优方案组合:

1. 先做域名白名单(CORS + 反向代理验证)

这是最基础的一层,能挡掉浏览器端的非法跨域请求,以及大部分小白爬虫。

配置CORS限制

用Express的cors包,只允许你的前端域名https://www.example.com发起请求:

const cors = require('cors');
app.use(cors({
  origin: 'https://www.example.com',
  credentials: true // 如果需要携带cookie(比如后续登录态),开启这个
}));

补充反向代理验证(防绕过CORS)

CORS是浏览器端的限制,爬虫可以用curl等工具直接绕过,所以要在后端加一层请求头校验:

// 先告诉Express信任Heroku的代理,这样能拿到真实的客户端请求头
app.set('trust proxy', true);

// 自定义中间件校验Origin/Referer
app.use((req, res, next) => {
  const allowedOrigin = 'https://www.example.com';
  // 优先取Origin,没有的话取Referer
  const requestSource = req.get('Origin') || req.get('Referer');
  
  // 校验请求来源是否合法
  if (!requestSource || !requestSource.startsWith(allowedOrigin)) {
    return res.status(403).json({ error: 'Forbidden: Invalid request source' });
  }
  next();
});

2. 加上请求频率限制(防暴力爬取)

即使是合法用户,也不能让爬虫无限次请求API。用express-rate-limit包设置合理的阈值:

const rateLimit = require('express-rate-limit');

const apiLimiter = rateLimit({
  windowMs: 1 * 60 * 1000, // 时间窗口:1分钟
  max: 100, // 每个IP最多100次请求
  message: { error: '请求过于频繁,请稍后再试' },
  standardHeaders: true,
  legacyHeaders: false
});

// 给所有API端点应用限制
app.use('/api/', apiLimiter);

注意:因为Heroku是代理环境,必须先设置app.set('trust proxy', true),否则rate-limit会把Heroku的代理IP当成客户端IP,导致所有请求共享同一个限制。

3. 签名请求(最高级的防爬方案)

如果需要更强的防护,这种方法能确保只有你的前端能发起有效请求,即使爬虫拿到了API地址,也没法构造合法请求。

实现思路

  1. 后端和前端(Next.js服务器端)共享一个密钥(存在环境变量里,不要硬编码);
  2. 前端每次请求API前,先调用Next.js的内部API路由生成签名;
  3. 后端验证签名的有效性,同时校验请求的时效性(防止重放攻击)。

代码示例

后端验证中间件

const crypto = require('crypto');

app.use((req, res, next) => {
  const { timestamp, signature } = req.query;
  const secret = process.env.API_SECRET; // 存在Heroku环境变量里

  // 校验必要参数
  if (!timestamp || !signature) {
    return res.status(403).json({ error: '缺少签名信息' });
  }

  // 校验签名是否过期(比如5分钟内有效)
  if (Date.now() - parseInt(timestamp) > 5 * 60 * 1000) {
    return res.status(403).json({ error: '签名已过期' });
  }

  // 生成预期签名并对比
  const expectedSignature = crypto.createHmac('sha256', secret)
    .update(`${req.method}${req.path}${timestamp}`)
    .digest('hex');

  if (signature !== expectedSignature) {
    return res.status(403).json({ error: '签名无效' });
  }

  next();
});

Next.js内部API路由(生成签名)

在pages/api/get-signature.js里:

import crypto from 'crypto';

export default function handler(req, res) {
  const { path, method } = req.query;
  const timestamp = Date.now().toString();
  const secret = process.env.API_SECRET; // 存在Vercel环境变量里

  const signature = crypto.createHmac('sha256', secret)
    .update(`${method}${path}${timestamp}`)
    .digest('hex');

  res.status(200).json({ timestamp, signature });
}

前端请求逻辑

const fetchPublicEvents = async () => {
  // 先从Next.js内部API获取签名
  const signatureRes = await fetch('/api/get-signature?path=/api/events&method=GET');
  const { timestamp, signature } = await signatureRes.json();

  // 带着签名请求后端API
  const apiRes = await fetch(`https://api.example.com/api/events?timestamp=${timestamp}&signature=${signature}`);
  return apiRes.json();
};

4. 辅助手段:User-Agent过滤

可以过滤掉明显的爬虫标识,比如curl、Scrapy等,虽然容易被绕过,但能挡掉一部分低级爬虫:

app.use((req, res, next) => {
  const blockedAgents = ['curl', 'Python-urllib', 'Scrapy', 'PostmanRuntime'];
  const userAgent = req.get('User-Agent') || '';
  
  if (blockedAgents.some(agent => userAgent.includes(agent))) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  next();
});

5. 别忘了用Helmet加固基础安全

虽然Helmet不防爬,但它能帮你设置关键安全头,比如:

const helmet = require('helmet');
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      connectSrc: ["'self'", "https://api.example.com"] // 限制前端只能从你的API拉数据
    }
  },
  xFrameOptions: 'DENY', // 防止点击劫持
  xXssProtection: true // 启用XSS防护
}));

方案优先级建议

  1. 先配置CORS+反向代理验证,快速挡掉大部分非法请求;
  2. 加上请求频率限制,防止暴力爬取;
  3. 如果需要高安全性,再实现签名请求;
  4. User-Agent过滤作为辅助;
  5. Helmet一定要配置,加固基础安全。

注意:测试时要确保Next.js的SSR/SSG请求能正常通过(因为这类请求是从Vercel服务器发起的,要确保Origin/Referer能被正确识别)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 12:12:33