如何通过一次 API 调用检测应用中的 VPN 用户
将 VPN、代理和 Tor 检测添加到注册、结账和登录流程中。 Express 中间件、Next.js 集成以及带有工作代码的风险评分示例。
您的结帐页面在 12 小时内收到来自同一 IP 范围的 50 个订单,全部使用预付卡。 您的免费试用显示一周内有 200 个来自数据中心 IP 的注册。 您的登录端点看到 来自轮换代理 IP 的凭证填充尝试。
您需要知道流量何时来自 VPN、代理或 Tor 出口节点。 不去阻止它 直接,但要调整您的风险评分。 一次 API 调用就会向您发出该信号。
API 调用
将用户的IP发送至 POST /v1/vpn-detect。 无依赖关系,无需 SDK。
curl -X POST https://api.botoi.com/v1/vpn-detect \\
-H "Content-Type: application/json" \\
-d '{"ip": "185.220.101.1"}'
对已知 Tor 出口节点的响应(风险评分 90):
{
"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 的响应(风险评分 0):
{
"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
}
}
}
响应为您提供了五个布尔标志(is_vpn, is_proxy,
is_tor, is_datacenter) 加一个数字 risk_score
从 0 到 100。Tor 连接得分 90。数据中心 IP 得分 60。可疑主机名
得分 40。清洁住宅 IP 得分 0。
集成1:Express中间件
该中间件调用 VPN 检测 API 并将结果附加到 req.vpnRisk。
每个下游路由处理程序都可以检查 req.vpnRisk.isVpn 做出决定
无需重复API调用。
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;
interface VpnRisk {
isVpn: boolean;
isProxy: boolean;
isTor: boolean;
isDatacenter: boolean;
riskScore: number;
}
declare global {
namespace Express {
interface Request {
vpnRisk?: VpnRisk;
}
}
}
export async function vpnDetectMiddleware(
req: Request,
_res: Response,
next: NextFunction
) {
const ip = req.headers['x-forwarded-for']?.toString().split(',')[0]?.trim()
|| req.socket.remoteAddress
|| 'unknown';
try {
const res = await fetch(VPN_DETECT_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': \`Bearer \${BOTOI_API_KEY}\`,
},
body: JSON.stringify({ ip }),
signal: AbortSignal.timeout(3000),
});
const { data } = await res.json();
req.vpnRisk = {
isVpn: data.is_vpn,
isProxy: data.is_proxy,
isTor: data.is_tor,
isDatacenter: data.is_datacenter,
riskScore: data.risk_score,
};
} catch {
// Fail open: if detection fails, treat as clean
req.vpnRisk = {
isVpn: false,
isProxy: false,
isTor: false,
isDatacenter: false,
riskScore: 0,
};
}
next();
}
// Usage in your route:
// app.use(vpnDetectMiddleware);
//
// app.post('/api/signup', (req, res) => {
// if (req.vpnRisk?.isVpn) {
// // require email verification or flag for review
// }
// });
中间件打开失败。 如果 API 无法访问或 3 秒后超时,则会设置
所有标志到 false 并让请求继续。 您的用户永远不会看到错误
由第三方中断造成的。
集成 2:Next.js 结帐保护
结帐欺诈遵循以下模式:新帐户、预付卡、VPN 连接。 这个Next.js App Router 路由处理程序检查所有三个信号并将可疑订单路由至手动 审查而不是自动批准它们。
import { NextRequest, NextResponse } from 'next/server';
const VPN_DETECT_URL = 'https://api.botoi.com/v1/vpn-detect';
const BOTOI_API_KEY = process.env.BOTOI_API_KEY!;
interface CheckoutBody {
cardType: 'credit' | 'debit' | 'prepaid';
accountCreatedAt: string;
amount: number;
currency: string;
}
export async function POST(req: NextRequest) {
const body: CheckoutBody = await req.json();
const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim()
|| '127.0.0.1';
// Check VPN status
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(3000),
});
const { data: vpnData } = await vpnRes.json();
const accountAge = Date.now() - new Date(body.accountCreatedAt).getTime();
const isNewAccount = accountAge < 24 * 60 * 60 * 1000; // less than 24 hours
const isPrepaid = body.cardType === 'prepaid';
const isVpn = vpnData.is_vpn || vpnData.is_tor || vpnData.is_proxy;
// VPN + new account + prepaid card = manual review
if (isVpn && isNewAccount && isPrepaid) {
return NextResponse.json({
status: 'review',
orderId: crypto.randomUUID(),
message: 'Order placed. We will confirm within 30 minutes.',
}, { status: 202 });
}
// VPN + new account (no prepaid) = proceed with logging
if (isVpn && isNewAccount) {
console.log(JSON.stringify({
event: 'checkout_vpn_new_account',
ip,
riskScore: vpnData.risk_score,
amount: body.amount,
}));
}
// Process the order normally
return NextResponse.json({
status: 'approved',
orderId: crypto.randomUUID(),
});
}
处理程序不会拒绝该订单。 它返回 202 并显示“我们将在 30 分钟内确认” 消息。 这可以为您的团队赢得时间进行审查,而不会向坏人举报他们的行为 已标记。 VPN 上的合法客户在短暂延迟后仍能处理订单。
集成3:登录速率限制
撞库攻击通常来自 VPN 或代理 IP,以避免基于 IP 的阻止。 对这些连接应用更严格的速率限制:VPN 用户每 15 分钟尝试 3 次登录 而普通用户则为 10 个。
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;
// VPN users: 3 attempts per 15 minutes
// Regular users: 10 attempts per 15 minutes
const VPN_LOGIN_LIMIT = 3;
const STANDARD_LOGIN_LIMIT = 10;
const WINDOW_MS = 15 * 60 * 1000;
const loginAttempts = new Map<string, { count: number; resetAt: number }>();
export async function loginRateLimit(
req: Request,
res: Response,
next: NextFunction
) {
const ip = req.headers['x-forwarded-for']?.toString().split(',')[0]?.trim()
|| req.socket.remoteAddress
|| 'unknown';
// Check VPN status
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
}
const limit = isVpn ? VPN_LOGIN_LIMIT : STANDARD_LOGIN_LIMIT;
const now = Date.now();
const entry = loginAttempts.get(ip);
if (!entry || entry.resetAt < now) {
loginAttempts.set(ip, { count: 1, resetAt: now + WINDOW_MS });
return next();
}
entry.count++;
if (entry.count > limit) {
const retryAfter = Math.ceil((entry.resetAt - now) / 1000);
return res.status(429).json({
error: 'Too many login attempts. Try again later.',
retryAfter,
});
}
next();
}
// Mount on your login route:
// app.post('/api/auth/login', loginRateLimit, loginHandler);
3:10 的比率可以减慢来自 VPN IP 的自动攻击,而不会影响大多数真实用户。 企业 VPN 上的合法用户如果输错密码 3 次,仍然会收到 清除错误消息和重试窗口,而不是永久禁止。
建立复合风险评分
VPN 检测本身就是一个微弱的欺诈信号。 许多合法用户都运行 VPN。 信号得到 当你将它与其他检查结合起来时会更强大。 并行调用三个 botoi 端点:
/v1/vpn-detect连接类型(VPN、代理、Tor、数据中心)/v1/disposable-email/check电子邮件质量(一次性与永久)/v1/ip/lookup地理不匹配(IP 国家/地区与帐单国家/地区)
此函数调用所有三个函数并生成 0-100 的风险评分:
interface RiskResult {
score: number;
action: 'allow' | 'review' | 'block';
signals: {
vpn: boolean;
tor: boolean;
proxy: boolean;
vpnRiskScore: number;
disposableEmail: boolean;
geoMismatch: boolean;
ipCountry: string;
billingCountry: string;
};
}
async function calculateRisk(
ip: string,
email: string,
billingCountry: string
): Promise<RiskResult> {
const BOTOI_KEY = process.env.BOTOI_API_KEY!;
const headers = {
'Content-Type': 'application/json',
'Authorization': \`Bearer \${BOTOI_KEY}\`,
};
// Run all three checks in parallel
const [vpnRes, emailRes, geoRes] = await Promise.all([
fetch('https://api.botoi.com/v1/vpn-detect', {
method: 'POST',
headers,
body: JSON.stringify({ ip }),
}),
fetch('https://api.botoi.com/v1/disposable-email/check', {
method: 'POST',
headers,
body: JSON.stringify({ email }),
}),
fetch('https://api.botoi.com/v1/ip/lookup', {
method: 'POST',
headers,
body: JSON.stringify({ ip }),
}),
]);
const vpnData = (await vpnRes.json()).data;
const emailData = (await emailRes.json()).data;
const geoData = (await geoRes.json()).data;
const ipCountry = geoData.country_code || '';
const geoMismatch = ipCountry !== '' && billingCountry !== ''
&& ipCountry.toUpperCase() !== billingCountry.toUpperCase();
// Weight each signal
let score = 0;
// VPN/proxy/Tor: up to 30 points
if (vpnData.is_vpn || vpnData.is_tor || vpnData.is_proxy) {
score += Math.round(vpnData.risk_score * 0.3);
}
// Disposable email: 25 points
if (emailData.is_disposable) {
score += 25;
}
// Geo mismatch (IP country != billing country): 20 points
if (geoMismatch) {
score += 20;
}
// VPN + disposable email combo: extra 15 points
if ((vpnData.is_vpn || vpnData.is_tor) && emailData.is_disposable) {
score += 15;
}
score = Math.min(score, 100);
return {
score,
action: score > 70 ? 'block' : score > 30 ? 'review' : 'allow',
signals: {
vpn: vpnData.is_vpn,
tor: vpnData.is_tor,
proxy: vpnData.is_proxy,
vpnRiskScore: vpnData.risk_score,
disposableEmail: emailData.is_disposable,
geoMismatch,
ipCountry,
billingCountry,
},
};
}
// Example usage:
// const risk = await calculateRisk('185.220.101.1', 'user@tempmail.com', 'US');
// if (risk.action === 'review') { queueForManualReview(orderId); }
// if (risk.action === 'block') { rejectTransaction(orderId); }
所有三个 API 调用并行运行 Promise.all,所以总延迟等于
最慢的调用(通常低于 100 毫秒)。 评分权重是一个起点。 调整它们
根据您的欺诈数据。 如果一次性电子邮件是您退款的最大来源,请增加
那个重量。 如果地理不匹配很少见,并且通常对您的用户群来说是良性的,请减少它。
何时不应阻止 VPN 用户
对于大多数应用程序来说,硬阻止 VPN 流量是一个错误。 以下是常见原因 人们通过 VPN 连接:
- 公司政策。 默认情况下,公司通过 VPN 路由员工流量。 阻止这些连接意味着您的 B2B 客户无法在工作时间使用您的产品。
- 隐私。 注重隐私的用户在每个连接上运行 VPN 作为基准 安全措施。 他们是付费客户,而不是欺诈者。
- 互联网访问受到限制。 某些国家/地区的用户依靠 VPN 来访问 您的产品。 阻止 VPN 会将其完全拒之门外。
- 公共无线网络。 咖啡店或机场网络上的任何人都应该使用 VPN。 因良好的安全卫生而惩罚他们会产生错误的激励。
- 记者和研究人员。 担任这些角色的人员使用 Tor 和 VPN 来 源头保护和操作安全。 阻止它们可能会产生巨大的后果。
正确的方法是:标记并得分,不要硬阻挡。 使用 VPN 检测作为一个输入 考虑多个信号的风险函数。 将高风险事务路由到审核队列。 让人类对模棱两可的案件做出最终决定。
要点
-
POST /v1/vpn-detect回报is_vpn,is_proxy,is_tor,is_datacenter, 和risk_score对于任何IP。 - 测试不需要 API 密钥(每分钟 5 个请求)。 免费钥匙解锁更高限制 for production.
- 将 VPN 检查附加到 Express 中间件,以便每条路由都可以访问风险数据 无需重复调用。
- 将 VPN 检测与一次性电子邮件检查和 IP 地理定位结合起来 风险评分足够强,可以采取行动。
- 标记 VPN 连接以供审查。 不要阻止他们。 合法用户运行 VPN 隐私、公司政策和限制互联网访问。
FAQ
- 如何在我的应用程序中检测 VPN 用户?
- 将 POST 请求中的用户 IP 地址发送到 botoi /v1/vpn-detect 端点。 响应包括 is_vpn、is_proxy、is_tor 和 is_datacenter 的布尔标志,以及 0-100 的risk_score。 在注册、登录或结账期间调用此端点以标记来自匿名服务的连接。
- 哪种 VPN 检测 API 最适合生产应用程序?
- 寻找一个为 VPN、代理、Tor 和数据中心连接返回单独标志而不是单个布尔值的 API。 botoi /v1/vpn-Detect 端点返回所有四个标志以及数字风险评分,并且无需 API 密钥即可以每分钟 5 个请求的速度运行。 对于生产工作负载,API 密钥从免费套餐开始解锁更高的速率限制。
- 我应该阻止所有 VPN 用户使用我的应用程序吗?
- 不会。许多合法用户出于隐私、公司政策或因为居住在互联网访问受限的地区而运行 VPN。 阻止所有 VPN 流量可将付费客户拒之门外。 相反,应使用 VPN 检测作为复合风险评分中的一个信号,并标记可疑连接以供审查。
- 我可以使用相同的 API 调用检测代理和 Tor 连接吗?
- 是的。 botoi /v1/vpn-detect 端点在单个响应中返回 is_vpn、is_proxy 和 is_tor 的单独布尔标志。 您不需要为每种连接类型单独调用 API。 该端点还返回 is_datacenter 以识别来自 AWS 或 Google Cloud 等云提供商的流量。
- 如何将 VPN 检测与其他欺诈信号结合起来?
- 并行调用多个 botoi 端点:/v1/vpn-detect 用于连接类型,/v1/disposable-email/check 用于电子邮件质量,以及 /v1/ip/lookup 用于 IP 国家/地区和账单国家/地区之间的地理不匹配。 对每个信号进行加权并将其求和为 0-100 的风险评分。 70分以上进入人工审核; 30分以下通过。
开始使用 botoi 构建
150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。