跳转到内容
Guide

VPN 和代理检测 API:标记滥用而不阻止用户

| 7 min read

通过一个 POST 请求检测 VPN、代理、Tor 和数据中心连接。 包括 Next.js 中间件、Express 速率限制和欺诈评分示例。

Digital shield icon with network connections
Photo by Privecstasy on Unsplash

您的 SaaS 应用程序为每位用户提供免费试用。 用户注册、激活 VPN,然后再次注册。 滥用促销会损失您的收入并扭曲您的转化指标。 您需要标记 VPN 和代理 注册时的连接。

本指南涵盖了 botoi POST /v1/vpn-detect 端点:它返回什么,如何返回 将其集成到 Next.js 和 Express 应用程序中,如何将其与其他欺诈信号相结合,以及在哪里 它达不到要求。

终点

正文中包含 IP 地址的一个 POST 请求。 没有特殊标头,不需要 API 密钥 匿名访问。

curl -X POST https://api.botoi.com/v1/vpn-detect \\
  -H "Content-Type: application/json" \\
  -d '{ "ip": "185.220.101.1" }'

对已知 Tor 出口节点的响应:

{
  "success": true,
  "data": {
    "ip": "185.220.101.1",
    "is_vpn": true,
    "is_proxy": false,
    "is_tor": true,
    "is_datacenter": false,
    "provider": null,
    "risk_score": 90,
    "checks": {
      "tor": true,
      "datacenter": false,
      "suspicious_hostname": false
    }
  }
}

对干净住宅IP的响应:

{
  "success": true,
  "data": {
    "ip": "73.162.45.118",
    "is_vpn": false,
    "is_proxy": false,
    "is_tor": false,
    "is_datacenter": false,
    "provider": null,
    "risk_score": 0,
    "checks": {
      "tor": false,
      "datacenter": false,
      "suspicious_hostname": false
    }
  }
}

响应字段

  • 是VPN (布尔值):如果 IP 属于已知数据中心范围或具有包含 VPN 相关关键字的可疑反向 DNS 主机名,则为 True。
  • 是代理 (布尔值):如果反向 DNS 主机名建议代理服务器,则为 true。
  • is_tor (布尔值):如果 IP 与已知的 Tor 出口节点匹配,则为 True。
  • 是_数据中心 (布尔值):如果 IP 属于 AWS、Google Cloud、Azure、DigitalOcean 或 Linode CIDR 范围,则为 True。
  • 提供者 (字符串或空):云提供商名称 is_datacenter 是真的。 对于住宅和 Tor IP 为空。
  • 风险评分 (数字,0-100):Tor 连接得分 90,数据中心 IP 得分 60,可疑主机名得分 40。干净的住宅 IP 得分 0。
  • 检查 (object):触发了哪些检测方法的故障,用于调试。

使用 Next.js 中间件在注册时标记 VPN 用户

该中间件拦截对您的注册路由的 POST 请求,根据调用者的 IP 检查调用者的 IP VPN 检测 API,并在检测到 VPN 时将标头附加到请求中。 您的注册管理员 读取标题并决定做什么:要求电子邮件验证、添加手动审核标志,或者 缩短试用期。

import { NextRequest, NextResponse } from 'next/server';

const VPN_DETECT_URL = 'https://api.botoi.com/v1/vpn-detect';

export async function middleware(req: NextRequest) {
  if (req.method !== 'POST') {
    return NextResponse.next();
  }

  const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim()
    || req.ip
    || '127.0.0.1';

  try {
    const res = await fetch(VPN_DETECT_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ip }),
      signal: AbortSignal.timeout(3000),
    });

    const { data } = await res.json();

    if (data.is_vpn || data.is_tor || data.is_proxy) {
      // Add a header so your signup handler can flag the account
      const response = NextResponse.next();
      response.headers.set('x-vpn-detected', 'true');
      response.headers.set('x-vpn-risk-score', String(data.risk_score));
      return response;
    }
  } catch {
    // Fail open: if the API is unreachable, let the request through
    console.warn('VPN detection check failed, allowing request');
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/api/auth/signup', '/api/auth/register'],
};

中间件不会阻止注册。 它将信号传递给您的处理程序。 这是正确的 方法,因为 VPN 流量并不能证明欺诈。 使用公司 VPN 或旅行的用户 通过限制性网络是合法客户。

Express 中 VPN IP 的更严格的速率限制

如果您运行 API,则可以对 VPN 和代理连接应用更严格的速率限制,而不会阻塞 他们直接。 该中间件为标准用户每小时提供 100 个请求,为 VPN 用户提供 20 个请求。

import type { Request, Response, NextFunction } from 'express';

const VPN_DETECT_URL = 'https://api.botoi.com/v1/vpn-detect';
const BOTOI_API_KEY = process.env.BOTOI_API_KEY;

// Standard limits
const STANDARD_LIMIT = 100; // requests per hour
const VPN_LIMIT = 20;       // requests per hour for VPN users

const requestCounts = new Map<string, { count: number; resetAt: number }>();

export async function vpnAwareRateLimit(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const ip = req.headers['x-forwarded-for']?.toString().split(',')[0]?.trim()
    || req.socket.remoteAddress
    || 'unknown';

  let isVpn = false;

  try {
    const vpnRes = await fetch(VPN_DETECT_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': \`Bearer \${BOTOI_API_KEY}\`,
      },
      body: JSON.stringify({ ip }),
      signal: AbortSignal.timeout(2000),
    });

    const { data } = await vpnRes.json();
    isVpn = data.is_vpn || data.is_tor || data.is_proxy;
  } catch {
    // Fail open: use standard limits if detection fails
  }

  const limit = isVpn ? VPN_LIMIT : STANDARD_LIMIT;
  const now = Date.now();
  const entry = requestCounts.get(ip);

  if (!entry || entry.resetAt < now) {
    requestCounts.set(ip, { count: 1, resetAt: now + 3600_000 });
    res.setHeader('X-RateLimit-Limit', limit);
    return next();
  }

  entry.count++;

  if (entry.count > limit) {
    return res.status(429).json({
      error: 'Rate limit exceeded',
      retryAfter: Math.ceil((entry.resetAt - now) / 1000),
    });
  }

  res.setHeader('X-RateLimit-Limit', limit);
  res.setHeader('X-RateLimit-Remaining', limit - entry.count);
  next();
}

标准限制和 VPN 限制之间的 5:1 比例是一个起点。 根据您的滥用情况进行调整 模式。 如果您的 API 处理付款或帐户修改,则更严格的 VPN 限制是有意义的。 对于只读端点,您可能根本不需要差异限制。

欺诈评分:将 VPN 检测与其他信号相结合

VPN 检测本身就是一个微弱的欺诈信号。 VPN + 一次性电子邮件 + 新帐户 + 失败 付款尝试是一个强烈的信号。 该功能将多个输入组合成一个欺诈行为 得分。

interface FraudSignals {
  vpnDetected: boolean;
  riskScore: number;
  disposableEmail: boolean;
  accountAge: number; // days
  failedPayments: number;
}

function calculateFraudScore(signals: FraudSignals): number {
  let score = 0;

  // VPN/proxy risk contributes up to 30 points
  if (signals.vpnDetected) {
    score += Math.round(signals.riskScore * 0.3);
  }

  // Disposable email: strong signal
  if (signals.disposableEmail) {
    score += 35;
  }

  // New account + VPN is a red flag
  if (signals.accountAge < 1 && signals.vpnDetected) {
    score += 20;
  }

  // Failed payment history
  score += Math.min(signals.failedPayments * 10, 30);

  return Math.min(score, 100);
}

async function assessSignupRisk(ip: string, email: string) {
  const [vpnRes, emailRes] = await Promise.all([
    fetch('https://api.botoi.com/v1/vpn-detect', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ip }),
    }),
    fetch('https://api.botoi.com/v1/disposable-email/check', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email }),
    }),
  ]);

  const vpnData = (await vpnRes.json()).data;
  const emailData = (await emailRes.json()).data;

  const fraudScore = calculateFraudScore({
    vpnDetected: vpnData.is_vpn || vpnData.is_tor,
    riskScore: vpnData.risk_score,
    disposableEmail: emailData.is_disposable,
    accountAge: 0, // new signup
    failedPayments: 0,
  });

  return {
    fraudScore,
    action: fraudScore > 70 ? 'block' : fraudScore > 40 ? 'review' : 'allow',
    details: {
      vpn: vpnData.is_vpn,
      tor: vpnData.is_tor,
      proxy: vpnData.is_proxy,
      disposableEmail: emailData.is_disposable,
    },
  };
}

两个 API 调用并行运行,因此总延迟是两者中较慢的一个(通常低于 100 毫秒)。 这 action 字段为您提供了三个级别:允许、审查或阻止。 对于分数 在 40 到 70 之间,将注册路由到手动审核队列,而不是自动拒绝它。

缓存以减少 API 调用

IP 地址不会在每次请求时更改其 VPN 状态。 将结果缓存10分钟 减少 API 使用,而不会错过状态更改。

const vpnCache = new Map<string, { result: VpnResult; expiresAt: number }>();
const CACHE_TTL = 10 * 60 * 1000; // 10 minutes

interface VpnResult {
  isVpn: boolean;
  isTor: boolean;
  isProxy: boolean;
  riskScore: number;
}

async function checkVpn(ip: string): Promise<VpnResult> {
  const cached = vpnCache.get(ip);
  if (cached && cached.expiresAt > Date.now()) {
    return cached.result;
  }

  try {
    const res = await fetch('https://api.botoi.com/v1/vpn-detect', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ip }),
      signal: AbortSignal.timeout(3000),
    });

    const { data } = await res.json();
    const result: VpnResult = {
      isVpn: data.is_vpn,
      isTor: data.is_tor,
      isProxy: data.is_proxy,
      riskScore: data.risk_score,
    };

    vpnCache.set(ip, { result, expiresAt: Date.now() + CACHE_TTL });
    return result;
  } catch {
    return { isVpn: false, isTor: false, isProxy: false, riskScore: 0 };
  }
}

对于多服务器部署,请将内存中的映射替换为 Redis 或 Upstash。 相同的缓存键 (IP 地址)和 TTL 模式适用。

此 API 无法检测到的内容

对局限性的诚实比华丽的推销更重要。 这里是VPN检测的地方 达不到要求。

  • 住宅 VPN。 iCloud Private Relay 等服务和一些配置 的 Mulvad 通过住宅 IP 地址路由流量。 这些 IP 看起来相同 常规家庭互联网连接。 反向 DNS 或基于 CIDR 的检测无法捕获它们。
  • 移动运营商 NAT。 移动运营商使用运营商级 NAT,这意味着 数以千计的用户共享一个 IP 地址。 标记这些 IP 会影响合法用户。 API 可能会返回 is_datacenter: falserisk_score: 0 对于这些 即使 VPN 用户在 IP 后面也是如此。
  • 私有 SOCKS5 代理。 代理托管在住宅的个人服务器上 ISP 不会出现在数据中心 CIDR 范围中,并且没有可疑的主机名。 他们是 自动检测不可见。
  • 仅 IPv6 连接。 当前端点仅支持 IPv4 地址。 IPv6 VPN 检测不可用。
  • 共享主机上的误报。 一名开发人员正在运行一个业余项目 DigitalOcean 水滴将触发 is_datacenter: true。 这并不意味着他们是 隐藏他们的身份。

该检测非常适合商业 VPN 提供商(NordVPN、ExpressVPN、Surfshark、CyberGhost) 和 Tor 流量。 它捕获大多数数据中心托管的代理。 它无法捕获住宅 VPN 或 私人代理。 预计常见情况的检测率为 80-90%,边缘情况的检测率接近于零。

标记,不要阻止

对于大多数应用程序来说,彻底阻止 VPN 用户是一个错误。 原因如下:

  • 注重隐私且无意滥用您的服务的用户默认运行 VPN。
  • 使用公司 VPN 的员工通过公司基础设施路由所有流量。
  • 互联网受到限制的国家/地区的用户完全依赖 VPN 来访问您的产品。
  • 记者、活动家和安全研究人员出于合法原因使用 Tor。

正确的方法:向帐户添加风险标记,需要额外验证(电子邮件 确认、电话号码、付款方式),或将注册路由到审核队列。 让人类 对模棱两可的案件做出最后决定。

要点

  • POST /v1/vpn-detect 回报 is_vpn, is_proxy, is_tor, is_datacenter, provider, 和 risk_score 对于任何 IPv4 地址。
  • 匿名访问不需要 API 密钥(每分钟 5 个请求)。 免费钥匙解锁 500 个 每天的请求数。
  • 检测涵盖商业 VPN 提供商、已知的 Tor 出口节点和主要云提供商 IP 范围。 住宅 VPN 和私人代理可以通过。
  • 将 VPN 检测与一次性电子邮件检查、帐户年龄和付款历史记录相结合 有意义的欺诈分数。 仅 VPN 状态不足以采取行动。
  • 标记 VPN 连接以供审查。 不要阻止他们。 合法用户为了隐私而运行 VPN, 公司政策以及限制区域的访问。

FAQ

如何在我的应用程序中检测 VPN 用户?
将用户的 IP 地址发送到 VPN 检测 API(例如 POST /v1/vpn-detect)并检查响应中的 is_vpn 布尔值。 该 API 还返回 is_proxy、is_tor 和 is_datacenter 标志,以便您可以区分不同的匿名方法。 在注册、登录或结帐期间调用此端点以标记可疑连接以供审查。
VPN 检测 API 能否捕获每个 VPN 连接?
不会。VPN 检测的工作原理是检查已知的数据中心 IP 范围、反向 DNS 主机名和 Tor 退出节点列表。 住宅 VPN 服务通过家庭 ISP 地址路由流量,这看起来与常规住宅流量相同。 商业 VPN(NordVPN、ExpressVPN、Surfshark)的检测率预计为 80-90%,但住宅 VPN 和私人代理的检测率较低。
我应该阻止所有 VPN 用户访问我的应用程序吗?
不会。许多合法用户出于隐私、公司政策或因为居住在互联网访问受限的地区而运行 VPN。 彻底阻止 VPN 流量将导致付费客户无法使用。 相反,将 VPN 连接标记为较高风险,并将其与其他信号(电子邮件域、支付方式、帐户期限)结合起来做出决定。
VPN、代理和 Tor 检测之间有什么区别?
VPN 对通过隧道到服务器的所有流量进行加密,服务器通常由商业提供商运行。 代理通过中间服务器路由流量,无需完全加密。 Tor 通过多个志愿者操作的中继路由流量,以实现最大程度的匿名性。 botoi API 为每种类型返回单独的布尔标志,因此您可以对每种类型应用不同的策略。
botoi VPN 检测 API 是否需要 API 密钥?
不需要。匿名访问允许每分钟 5 个请求,无需 API 密钥。 对于生产工作负载,免费的 API 密钥可将限制提高到每天 500 个请求。 付费计划起价为 9 美元/月,费率限额更高。

开始使用 botoi 构建

150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。