教程:如何在 Node.js Express 中检测 VPN 和 Tor 用户

发布: (2025年12月16日 GMT+8 11:46)
5 min read
原文: Dev.to

Source: Dev.to

概述

如果你运营任何公共 API、SaaS 或论坛,你已经深知其中的痛点:bot traffic
你因垃圾信息封禁用户,几秒钟后他们就换了个新账号回来,因为他们切换了 VPN。你封锁一个 IP,他们就切换到 Tor 出口节点。

在本教程中,我将向你展示如何在你的 Node.js 应用中检测 non‑residential IPs(VPN、代理和托管中心),以便在它们触及你的数据库之前将其阻止——或至少通过 CAPTCHA 进行挑战。

目标

我们想要在 Express 中实现一个如下所示的中间件函数:

app.use((req, res, next) => {
  if (isHighRisk(req.ip)) {
    return res.status(403).send("VPNs are not allowed.");
  }
  next();
});

下面是构建方法。

方法 1: “硬核”方式(自行托管列表)

步骤 1:获取数据

  • Tor 退出节点 – Tor 项目会发布退出地址列表。
  • 云服务 IP 段 – AWS 和 Google 在巨大的 JSON 文件中公布它们的 IP 段。

您需要下载这些文件(例如 tor-exit-nodes.txtaws-ip-ranges.json),并保持它们为最新状态。

步骤 2:代码

const fs = require('fs');
const ipRangeCheck = require('ip-range-check'); // npm install ip-range-check

// Load the massive lists into memory (careful with RAM!)
const torNodes = fs.readFileSync('tor-exit-nodes.txt', 'utf8')
  .split('\n')
  .filter(Boolean);
const awsRanges = JSON.parse(
  fs.readFileSync('aws-ip-ranges.json', 'utf8')
).prefixes.map(p => p.ip_prefix);

function isHighRisk(userIp) {
  // Check if IP is in the Tor list
  if (torNodes.includes(userIp)) return true;

  // Check if IP is in a Cloud Range (CPU intensive)
  if (ipRangeCheck(userIp, awsRanges)) return true;

  return false;
}

方法 1 的问题

  • 数据陈旧 – VPN 提供商会每日更换 IP。如果不进行每小时更新,您会错过大量攻击。
  • 占用内存 – 将数百万条 IP 加载到 Node.js 内存中可能导致服务器崩溃。
  • 误报 – 要区分合法的数据中心 IP 与恶意 VPN IP 往往很困难。

方法二: “简易” 方法(实时 API 查询)

步骤 1:获取免费 API 密钥

从提供商的网站获取免费密钥(无需信用卡)。

步骤 2:中间件

API 返回一个 trustScore(0‑100),以及 Tor 和 VPN 的标记。

const axios = require('axios');

async function checkRiskScore(req, res, next) {
  const userIp = req.ip;

  try {
    const response = await axios.get('https://candycorndb.com/api/public/ip-score', {
      params: { ip: userIp }
    });

    const { score, isTor, isVPN } = response.data;

    // BLOCK if it's a confirmed Tor node or very high risk
    if (isTor || score > 85) {
      return res.status(403).json({ error: 'Anonymizers not allowed.' });
    }

    // CHALLENGE if it's suspicious (e.g., DigitalOcean droplet)
    if (score >= 50) {
      // Insert CAPTCHA logic here…
      console.log(`Suspicious traffic from ${userIp}`);
    }

    next();
  } catch (err) {
    // Fail open: if the API is down, let the user in so you don’t block real people
    next();
  }
}

// Apply to your sensitive routes
app.post('/api/signup', checkRiskScore, (req, res) => {
  res.send("Account created!");
});

为什么这样更好

  • 即时扫描 – 如果 API 之前未见过该 IP,它会在 < 500 ms 内扫描开放端口和 ISP 数据,因此永远不会出现“未知”。
  • 无需维护 – 不需要下载每日 CSV 转储。
  • 节省内存 – 您的 Node 服务器处理逻辑,而不是存储庞大的 IP 列表。

Summary

阻止恶意 IP 是一场军备竞赛。如果你在构建一个小型业余项目,方法 1 是一次有趣的学习练习。对于生产环境的应用,将风险检测交给专用 API(方法 2)通常比你花在解封垃圾账号上的时间更省钱。

欢迎随时提问关于 IP 过滤逻辑的问题! 😅

Back to Blog

相关文章

阅读更多 »

创建您的第一个 MCP 应用

TL;DR MCP 应用为对话代理和其他 MCP 客户端带来交互式 UI。 本教程展示了如何创建一个既简单又强大的应用源代码……

实验性 Hono auth npm 包

我正在构建的东西:我正在创建一个 auth package,开发者可以将其直接放入他们的应用中,而无需编写常规的登录、注册、JWT、电子邮件验证等样板代码。