コンテンツへスキップ
Guide

VPN およびプロキシ検出 API: ユーザーをブロックせずに不正行為を報告します

| 7 min read

VPN、プロキシ、Tor、およびデータセンター接続を 1 つの POST リクエストで検出します。 Next.js ミドルウェア、Express レート制限、不正スコアリングの例が含まれています。

Digital shield icon with network connections
Photo by Privecstasy on Unsplash

SaaS アプリはユーザーごとに無料トライアルを提供します。 ユーザーはサインアップし、VPN をアクティブ化し、再度サインアップします。 プロモーションの悪用は収益を犠牲にし、コンバージョン指標を歪めます。 VPN とプロキシにフラグを立てる必要があります サインアップ時点での接続。

このガイドではボットイについて説明します POST /v1/vpn-detect エンドポイント: 何を返すのか、どのように返すのか それを Next.js および Express アプリに統合する方法、他の不正シグナルと組み合わせる方法、および場所 それは不足します。

エンドポイント

本文に IP アドレスを含む 1 つの 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
    }
  }
}

応答フィールド

  • is_vpn (ブール値): IP が既知のデータセンター範囲に属している場合、または VPN 関連のキーワードを含む疑わしいリバース DNS ホスト名がある場合は True。
  • is_proxy (ブール値): 逆引き DNS ホスト名がプロキシ サーバーを示唆する場合は True。
  • is_tor (ブール値): IP が既知の Tor 出口ノードと一致する場合は True。
  • is_datacenter (ブール値): IP が AWS、Google Cloud、Azure、DigitalOcean、または Linode CIDR 範囲内にある場合は True。
  • プロバイダー (文字列またはnull): クラウドプロバイダー名 is_datacenter それは本当です。 住宅用 IP および Tor IP の場合は無効です。
  • リスクスコア (数値、0 ~ 100): Tor 接続スコア 90、データセンター IP スコア 60、不審なホスト名スコア 40。クリーンな住宅用 IP スコア 0。
  • 小切手 (オブジェクト): デバッグ用にトリガーされた検出メソッドの内訳。

Next.js ミドルウェアを使用してサインアップ時に VPN ユーザーにフラグを立てる

このミドルウェアは、サインアップ ルートへの POST リクエストをインターセプトし、発信者の 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 接続とプロキシ接続をブロックせずに、より厳しいレート制限を適用できます。 彼らは完全に。 このミドルウェアは、標準ユーザーに 1 時間あたり 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 呼び出しが並行して実行されるため、合計のレイテンシーは 2 つのうち遅い方になります (通常は 100ミリ秒)。 の action フィールドには、許可、レビュー、ブロックの 3 つの階層が表示されます。 スコアについて 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 プライベート リレーなどのサービスと一部の構成 住宅用 IP アドレスを経由する Mullvad ルート トラフィックの割合。 これらの IP は同一に見えます 通常の家庭用インターネット接続。 逆引き DNS や CIDR ベースの検出ではそれらを検出できません。
  • モバイルキャリアNAT。 携帯電話会社はキャリアグレードの NAT を使用します。つまり、 何千人ものユーザーが単一の IP アドレスを共有します。 これらの IP にフラグを立てると、正規のユーザーに影響します。 API が返す場合があります is_datacenter: false そして risk_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_vpnis_proxyis_toris_datacenterprovider、 そして risk_score 任意の IPv4 アドレスの場合。
  • 匿名アクセスには API キーは必要ありません (1 分あたり 5 リクエスト)。 無料のキーで 500 個のロックを解除 1日あたりのリクエスト。
  • 検出は商用 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 キーが必要ですか?
いいえ。匿名アクセスでは、API キーなしで 1 分あたり 5 つのリクエストが許可されます。 実稼働ワークロードの場合、無料の API キーにより、制限が 1 日あたり 500 リクエストに引き上げられます。 有料プランは月額 9 ドルから始まり、レート制限が高くなります。

botoiで開発を始めよう

150以上のAPIエンドポイント。検索、テキスト処理、画像生成、開発者ユーティリティに対応。無料プラン、クレジットカード不要。