Перейти к содержимому
Integration

Как обнаружить пользователей VPN в вашем приложении с помощью одного вызова API

| 7 min read

Добавьте обнаружение VPN, прокси-сервера и Tor в процессы регистрации, оформления заказа и входа в систему. Промежуточное программное обеспечение Express, интеграция Next.js и примеры оценки рисков с рабочим кодом.

Lock icon on a digital network background representing VPN security
Photo by Towfiqu barbhuiya on Unsplash

На вашу страницу оформления заказа поступает 50 заказов с одного и того же диапазона IP-адресов за 12 часов, и все они выполняются с использованием предоплаченных карт. Ваша бесплатная пробная версия показывает 200 регистраций с IP-адресов центров обработки данных за неделю. Ваша конечная точка входа видит попытки ввода учетных данных с помощью ротации IP-адресов прокси.

Вам необходимо знать, когда трафик поступает от VPN, прокси-сервера или выходного узла Tor. Не для того, чтобы заблокировать это сразу, а для корректировки вашей оценки риска. One API call gives you that signal.

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: Экспресс-промежуточное ПО

Это промежуточное программное обеспечение вызывает API обнаружения VPN и присоединяет результат к 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: Ограничение скорости входа в систему

Атаки с подстановкой учетных данных часто происходят с IP-адресов VPN или прокси-сервера, чтобы избежать блокировки на основе IP. Примените более строгие ограничения скорости для этих подключений: 3 попытки входа в систему за 15 минут для пользователей VPN. против 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 замедляет автоматические атаки с IP-адресов VPN, не затрагивая при этом большинство реальных пользователей. Законный пользователь корпоративной VPN, который трижды вводит свой пароль с ошибкой, все равно получает четкое сообщение об ошибке и окно повторной попытки, а не постоянный бан.

Построение комплексной оценки риска

Обнаружение VPN само по себе является слабым сигналом мошенничества. Многие законные пользователи используют VPN. Сигнал получает сильнее, если объединить его с другими проверками. Вызовите три конечные точки ботоя параллельно:

  • /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 полностью блокирует их.
  • Общественный Wi-Fi. Любой пользователь сети кафе или аэропорта должен использовать VPN. Наказание их за соблюдение правил безопасности создает неправильный стимул.
  • Журналисты и исследователи. Люди на этих должностях используют Tor и VPN для защита источника и эксплуатационная безопасность. Их блокирование может иметь огромные последствия.

Правильный подход: отмечайте и оценивайте, а не жестко блокируйте. Используйте обнаружение VPN как один из входных данных для функция риска, которая учитывает несколько сигналов. Направляйте транзакции с высоким риском в очередь проверки. Позвольте людям сделать окончательный выбор в неоднозначных случаях.

Ключевые моменты

  • POST /v1/vpn-detect возвращает is_vpn, is_proxy, is_tor, is_datacenter, и risk_score для любого IP.
  • Для тестирования не требуется ключ API (5 запросов в минуту). Бесплатные ключи открывают более высокие лимиты для производства.
  • Прикрепите проверку VPN к промежуточному программному обеспечению Express, чтобы каждый маршрут имел доступ к данным о рисках. не повторяя звонок.
  • Объедините обнаружение VPN с одноразовыми проверками электронной почты и геолокацией IP для комплекса. уровень риска, который достаточно силен, чтобы действовать в соответствии с ним.
  • Отметьте VPN-подключения для проверки. Не блокируйте их. Законные пользователи используют VPN для конфиденциальность, корпоративная политика и ограниченный доступ в Интернет.

FAQ

Как обнаружить пользователей VPN в моем приложении?
Отправьте IP-адрес пользователя в запросе POST на конечную точку botoi /v1/vpn-detect. Ответ включает логические флаги для is_vpn, is_proxy, is_tor и is_datacenter, а также риск_оценку от 0 до 100. Вызовите эту конечную точку во время регистрации, входа в систему или оформления заказа, чтобы пометить соединения со стороны служб анонимизации.
Какой API обнаружения VPN лучше всего подходит для производственных приложений?
Ищите API, который возвращает отдельные флаги для подключений VPN, прокси, Tor и центра обработки данных, а не одно логическое значение. Конечная точка botoi /v1/vpn-detect возвращает все четыре флага плюс числовой показатель риска и работает без ключа API со скоростью 5 запросов в минуту. Для производственных рабочих нагрузок ключи API открывают более высокие ограничения скорости, начиная с бесплатного уровня.
Должен ли я заблокировать доступ всех пользователей VPN к моему приложению?
Нет. Многие законные пользователи используют VPN из соображений конфиденциальности, корпоративной политики или потому, что они живут в регионах с ограниченным доступом в Интернет. Блокировка всего VPN-трафика блокирует платежеспособных клиентов. Вместо этого используйте обнаружение VPN как один из сигналов в комплексной оценке риска и помечайте подозрительные соединения для проверки.
Могу ли я обнаружить соединения прокси и Tor с помощью одного и того же вызова API?
Да. Конечная точка 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-эндпоинтов для поиска, обработки текста, генерации изображений и утилит для разработчиков. Бесплатный тариф, без банковской карты.