Cómo detectar usuarios de VPN en su aplicación con una llamada API
Agregue VPN, proxy y detección de Tor a los flujos de registro, pago e inicio de sesión. Ejemplos de middleware Express, integración de Next.js y puntuación de riesgos con código de trabajo.
Su página de pago recibe 50 pedidos del mismo rango de IP en 12 horas, todos utilizando tarjetas prepagas. Su prueba gratuita muestra 200 registros desde IP de centros de datos en una semana. Su punto final de inicio de sesión ve intentos de relleno de credenciales desde IP de proxy rotativas.
Necesita saber cuándo el tráfico proviene de una VPN, un proxy o un nodo de salida de Tor. para no bloquearlo directamente, sino para ajustar su puntuación de riesgo. Una llamada API te da esa señal.
La llamada API
Enviar la IP del usuario a POST /v1/vpn-detect. Sin dependencias, no se requiere SDK.
curl -X POST https://api.botoi.com/v1/vpn-detect \\
-H "Content-Type: application/json" \\
-d '{"ip": "185.220.101.1"}'
Respuesta para un nodo de salida de Tor conocido (puntuación de riesgo 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
}
}
}
Respuesta para una IP residencial limpia (puntuación de riesgo 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
}
}
}
La respuesta le proporciona cinco indicadores booleanos (is_vpn, is_proxy,
is_tor, is_datacenter) Más una numérica risk_score
de 0 a 100. Las conexiones Tor obtienen una puntuación de 90. Las IP de los centros de datos obtienen una puntuación de 60. Nombres de host sospechosos
puntuación 40. IP residenciales limpias puntuación 0.
Integración 1: middleware exprés
Este middleware llama a la API de detección de VPN y adjunta el resultado a req.vpnRisk.
Cada controlador de ruta descendente puede verificar req.vpnRisk.isVpn para tomar decisiones
sin repetir la llamada 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
// }
// });
El middleware no se abre. Si no se puede acceder a la API o se agota el tiempo de espera después de 3 segundos, se establece
todas las banderas a false y deja que la solicitud continúe. Tus usuarios nunca ven un error
causado por una interrupción de terceros.
Integración 2: protección de pago de Next.js
El fraude en el pago sigue un patrón: cuenta nueva, tarjeta prepago, conexión VPN. Este siguiente.js El controlador de ruta de App Router verifica las tres señales y dirige las órdenes sospechosas al manual revisarlos en lugar de aprobarlos automáticamente.
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(),
});
}
El encargado no rechaza la orden. Devuelve un 202 con un "confirmaremos dentro de 30 minutos". mensaje. Esto le da tiempo a su equipo para revisar sin avisar a un mal actor que ha estado marcado. Los clientes legítimos de VPN aún procesan su pedido después de un breve retraso.
Integración 3: limitación de la tasa de inicio de sesión
Los ataques de relleno de credenciales a menudo provienen de IP VPN o proxy para evitar el bloqueo basado en IP. Aplique límites de velocidad más estrictos a esas conexiones: 3 intentos de inicio de sesión cada 15 minutos para usuarios de VPN versus 10 para los usuarios habituales.
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);
La proporción de 3:10 ralentiza los ataques automatizados desde IP de VPN sin afectar a la mayoría de los usuarios reales. Un usuario legítimo de una VPN corporativa que escribe mal su contraseña tres veces aún recibe una mensaje de error claro y una ventana de reintento, no una prohibición permanente.
Construyendo una puntuación de riesgo compuesta
La detección de VPN por sí sola es una señal débil de fraude. Muchos usuarios legítimos utilizan VPN. La señal llega más fuerte cuando lo combinas con otros controles. Llame a tres puntos finales de botoi en paralelo:
/v1/vpn-detectpara el tipo de conexión (VPN, proxy, Tor, centro de datos)/v1/disposable-email/checkpara la calidad del correo electrónico (desechable versus permanente)/v1/ip/lookuppor discrepancia geográfica (país de IP versus país de facturación)
Esta función llama a los tres y produce una puntuación de riesgo de 0 a 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); }
Las tres llamadas API se ejecutan en paralelo con Promise.all, por lo que la latencia total es igual
la llamada más lenta (normalmente menos de 100 ms). Los pesos de puntuación son un punto de partida. Sintonízalos
basado en sus datos de fraude. Si los correos electrónicos desechables son su mayor fuente de devoluciones de cargo, aumente
ese peso. Si las discrepancias geográficas son raras y generalmente benignas para su base de usuarios, redúzcalas.
Cuándo NO bloquear a los usuarios de VPN
Bloquear el tráfico VPN es un error para la mayoría de las aplicaciones. Aquí están las razones comunes la gente se conecta a través de una VPN:
- Política corporativa. Las empresas enrutan el tráfico de los empleados a través de una VPN de forma predeterminada. Bloquear estas conexiones significa que sus clientes B2B no pueden usar su producto durante el horario laboral.
- Privacidad. Los usuarios preocupados por la privacidad ejecutan VPN en cada conexión como punto de referencia medida de seguridad. Son clientes que pagan, no estafadores.
- Acceso restringido a Internet. Los usuarios de ciertos países dependen de las VPN para llegar su producto en absoluto. Bloquear las VPN las bloquea por completo.
- Wifi público. Cualquiera que esté en una cafetería o en la red de un aeropuerto debería utilizar un VPN. Penalizarlos por una buena higiene de seguridad crea un incentivo equivocado.
- Periodistas e investigadoras. Las personas en estos roles usan Tor y VPN para protección de fuentes y seguridad operativa. Bloquearlos puede tener consecuencias enormes.
El enfoque correcto: marcar y anotar, no bloquear con fuerza. Utilice la detección de VPN como entrada a un función de riesgo que considera múltiples señales. Enrute las transacciones de alto riesgo a una cola de revisión. Dejemos que los humanos tomen la decisión final en casos ambiguos.
Puntos clave
-
POST /v1/vpn-detectregresais_vpn,is_proxy,is_tor,is_datacenter, yrisk_scorepara cualquier IP. - No se requiere clave API para las pruebas (5 solicitudes por minuto). Las claves gratuitas desbloquean límites más altos para la producción.
- Adjunte la verificación de VPN al middleware Express para que cada ruta tenga acceso a los datos de riesgo sin repetir la llamada.
- Combine la detección de VPN con comprobaciones de correo electrónico desechables y geolocalización de IP para un complejo puntuación de riesgo que sea lo suficientemente fuerte como para actuar en consecuencia.
- Marcar conexiones VPN para su revisión. No los bloquees. Los usuarios legítimos ejecutan VPN para privacidad, política corporativa y acceso restringido a Internet.
FAQ
- ¿Cómo detecto usuarios de VPN en mi aplicación?
- Envíe la dirección IP del usuario en una solicitud POST al punto final botoi /v1/vpn-detect. La respuesta incluye indicadores booleanos para is_vpn, is_proxy, is_tor e is_datacenter, además de una puntuación de riesgo de 0 a 100. Llame a este punto final durante el registro, el inicio de sesión o el pago para marcar conexiones de servicios anónimos.
- ¿Qué API de detección de VPN es mejor para aplicaciones de producción?
- Busque una API que devuelva indicadores separados para conexiones VPN, proxy, Tor y centro de datos en lugar de un solo valor booleano. El punto final botoi /v1/vpn-detect devuelve los cuatro indicadores más una puntuación de riesgo numérica y funciona sin clave API a 5 solicitudes por minuto. Para cargas de trabajo de producción, las claves API desbloquean límites de velocidad más altos a partir del nivel gratuito.
- ¿Debo bloquear a todas las usuarios de VPN de mi aplicación?
- No. Muchos usuarios legítimos utilizan VPN por motivos de privacidad, políticas corporativas o porque viven en regiones con acceso restringido a Internet. Bloquear todo el tráfico VPN bloquea a los clientes que pagan. En su lugar, utilice la detección de VPN como una señal en una puntuación de riesgo compuesta y marque las conexiones sospechosas para su revisión.
- ¿Puedo detectar conexiones proxy y Tor con la misma llamada API?
- Sí. El punto final botoi /v1/vpn-detect devuelve indicadores booleanos separados para is_vpn, is_proxy e is_tor en una única respuesta. No necesita llamadas API independientes para cada tipo de conexión. El punto final también devuelve is_datacenter para identificar el tráfico de proveedores de nube como AWS o Google Cloud.
- ¿Cómo combino la detección de VPN con otras señales de fraude?
- Llame a varios puntos finales de botoi en paralelo: /v1/vpn-detect para el tipo de conexión, /v1/disposable-email/check para la calidad del correo electrónico y /v1/ip/lookup para la falta de coincidencia geográfica entre el país de IP y el país de facturación. Pondere cada señal y súmelas en una puntuación de riesgo de 0 a 100. Las puntuaciones superiores a 70 pasan a revisión manual; puntuaciones inferiores a 30 pasan.
Empieza a construir con botoi
150+ endpoints de API para consultas, procesamiento de texto, generacion de imagenes y utilidades para desarrolladores. Plan gratuito, sin tarjeta de credito.