1 回の API 呼び出しでアプリ内の VPN ユーザーを検出する方法
VPN、プロキシ、Tor 検出をサインアップ、チェックアウト、ログインのフローに追加します。 Express ミドルウェア、Next.js 統合、および実際に動作するコードを使用したリスク スコアリングの例。
チェックアウト ページは、12 時間以内に同じ IP 範囲から 50 件の注文を受け取ります。すべてプリペイド カードを使用しています。 無料トライアルでは、1 週間にデータセンター IP からの 200 件のサインアップが表示されます。 ログインエンドポイントが見る ローテーションプロキシ IP からのクレデンシャルスタッフィングの試行。
トラフィックがいつ VPN、プロキシ、または Tor 出口ノードから送信されるかを知る必要があります。 ブロックしないように 完全に、ただしリスクスコアを調整するためです。 1 つの 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
}
}
}
応答では 5 つのブール値フラグ (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 のルート ハンドラーは 3 つのシグナルをすべてチェックし、疑わしいオーダーを手動にルーティングします。 自動承認ではなくレビューしてください。
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(),
});
}
ハンドラーは注文を拒否しません。 「30 分以内に確認します」という内容の 202 が返されます。 メッセージ。 これにより、チームは、悪意のある行為を行ったことを知らせることなく、レビューする時間を稼ぐことができます。 フラグが立てられました。 VPN を使用している正規の顧客は、少し遅れて注文が処理されます。
統合 3: ログイン速度制限
Credential Stuffing 攻撃は、IP ベースのブロックを回避するために VPN またはプロキシ 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 を実行しています。 信号が得られます 他のチェックと組み合わせるとより強力になります。 3 つの botoi エンドポイントを並行して呼び出します。
/v1/vpn-detect接続タイプ (VPN、プロキシ、Tor、データセンター)/v1/disposable-email/check電子メールの品質 (使い捨てか永久か)/v1/ip/lookup地域の不一致 (IP 国と請求先国)
この関数は 3 つすべてを呼び出し、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); }
3 つの API 呼び出しはすべて並行して実行されます。 Promise.allしたがって、合計レイテンシーは次となります。
最も遅い呼び出し (通常は 100 ミリ秒未満)。 スコアリングウェイトは開始点です。 調整してください
あなたの詐欺データに基づいて。 使い捨てメールがチャージバックの最大の原因である場合は、増加させてください
その重さ。 地理的不一致がまれであり、通常はユーザー ベースにとって問題のない場合は、値を減らします。
VPN ユーザーをブロックしてはいけない場合
VPN トラフィックをハードブロックすることは、ほとんどのアプリケーションにとって間違いです。 一般的な理由は次のとおりです 人々は VPN 経由で接続します。
- 企業方針。 企業はデフォルトで従業員のトラフィックを VPN 経由でルーティングします。 これらの接続をブロックすると、B2B 顧客は勤務時間中に製品を使用できなくなります。
- プライバシー。 プライバシーを重視するユーザーは、ベースラインとしてすべての接続で VPN を実行します セキュリティ対策。 彼らは詐欺師ではなく顧客にお金を払っています。
- インターネットアクセスが制限されています。 特定の国のユーザーは、アクセスするために VPN に依存しています あなたの製品はまったく。 VPN をブロックすると、VPN は完全にロックアウトされます。
- 公衆Wi-Fi。 コーヒーショップや空港ネットワークに参加している人は誰でも、 VPN。 適切なセキュリティ衛生に対して罰則を与えると、間違ったインセンティブが生まれます。
- ジャーナリストや研究者。 これらの役割の人々は、Tor と VPN を次の目的で使用します。 ソースの保護と運用上のセキュリティ。 それらをブロックすると、甚大な影響が生じる可能性があります。
正しいアプローチ: フラグを立てて得点し、ハードブロックしないでください。 VPN 検出を 1 つの入力として使用します。 複数のシグナルを考慮したリスク関数。 リスクの高いトランザクションをレビューキューにルーティングします。 曖昧なケースの最終判断は人間に任せましょう。
重要なポイント
-
POST /v1/vpn-detect返品is_vpn、is_proxy、is_tor、is_datacenter、 そしてrisk_scoreあらゆる IP に対応します。 - テストには API キーは必要ありません (1 分あたり 5 リクエスト)。 無料キーでより高い制限を解除 生産用に。
- VPN チェックを Express ミドルウェアに接続して、すべてのルートがリスク データにアクセスできるようにします。 電話を繰り返さずに。
- VPN 検出と使い捨て電子メール チェックおよび化合物の IP 地理位置情報を組み合わせる 行動するのに十分な強さのリスクスコア。
- VPN 接続にレビュー用のフラグを立てます。 ブロックしないでください。 正規のユーザーが VPN を実行する プライバシー、企業ポリシー、インターネット アクセスの制限。
FAQ
- アプリ内で VPN ユーザーを検出するにはどうすればよいですか?
- POST リクエストでユーザーの IP アドレスを botoi /v1/vpn-detect エンドポイントに送信します。 応答には、is_vpn、is_proxy、is_tor、is_datacenter のブール型フラグに加えて、0 ~ 100 のリスクスコアが含まれます。 サインアップ、ログイン、またはチェックアウト中にこのエンドポイントを呼び出して、匿名化サービスからの接続にフラグを立てます。
- 本番アプリに最適な VPN 検出 API はどれですか?
- 単一のブール値ではなく、VPN、プロキシ、Tor、およびデータセンター接続の個別のフラグを返す API を探してください。 botoi /v1/vpn-detect エンドポイントは、4 つのフラグすべてと数値リスク スコアを返し、API キーなしで 1 分あたり 5 リクエストで動作します。 実稼働ワークロードの場合、API キーにより、無料枠から始まるより高いレート制限のロックが解除されます。
- すべての VPN ユーザーをアプリからブロックする必要がありますか?
- いいえ。多くの正当なユーザーは、プライバシー、企業ポリシー、またはインターネット アクセスが制限されている地域に住んでいるために VPN を実行しています。 すべての VPN トラフィックをブロックすると、料金を支払っている顧客が締め出されます。 代わりに、VPN 検出を複合リスク スコアの 1 つのシグナルとして使用し、疑わしい接続にフラグを立てて確認してください。
- 同じ API 呼び出しでプロキシ接続と Tor 接続を検出できますか?
- はい。 botoi /v1/vpn-detect エンドポイントは、is_vpn、is_proxy、is_tor の個別のブール フラグを 1 つの応答で返します。 接続タイプごとに個別の API 呼び出しを行う必要はありません。 エンドポイントは、AWS や Google Cloud などのクラウド プロバイダーからのトラフィックを識別するために is_datacenter も返します。
- VPN 検出を他の不正信号と組み合わせるにはどうすればよいですか?
- 複数の botoi エンドポイントを並行して呼び出します。接続タイプの場合は /v1/vpn-detect、電子メールの品質の場合は /v1/disposable-email/check、IP 国と請求先国の間の地理的不一致の場合は /v1/ip/lookup です。 各シグナルに重みを付け、それらを合計して 0 ~ 100 のリスク スコアを算出します。 70 を超えるスコアは手動レビューに進みます。 30 未満のスコアは通過します。
botoiで開発を始めよう
150以上のAPIエンドポイント。検索、テキスト処理、画像生成、開発者ユーティリティに対応。無料プラン、クレジットカード不要。