教程:如何在 Node.js Express 中检测 VPN 和 Tor 用户
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.txt、aws-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 过滤逻辑的问题! 😅