BotDetect v2 — 本番環境向けボット検出ライブラリ
重み付けスコアリング、行動分析、ブラウザフィンガープリンティング、設定可能なしきい値を備えたクライアントサイドのボットおよび自動化検出ライブラリ。ヘッドレスブラウザ、Selenium、Puppeteer、Playwright、CDPベースのツール、ステルス自動化フレームワークを検出します。
v2.1.0 — アンチ検出ハニーポット、GPU安定なキャンバスフィンガープリンティング、強化された行動分析、遅延初期化、サーバーサイド改ざん検出、リクエストフィンガープリントバインディング、レート制限。
目次
機能
- 28の検出モジュール — 自動化フレームワーク、ヘッドレスブラウザ、フィンガープリンティング、行動分析、ハニーポット、スタックトレーストラップを網羅
- 重み付けスコアリングシステム — 各シグナルは設定可能な重みを持ち、最終スコアはサーバーサイドで計算
- 3つの判定レベル:
human、suspicious、bot に対応するフリクションアクション(monitor、challenge、block)
- サーバーサイド検証 — nonceゲート、リプレイ防止、PoW署名
- スタックトレーストラップ — DOM APIをモンキーパッチして自動化ツールのコールスタックを取得
- 行動分析 — マウスの曲線、キーストロークタイミングの分散、スクロール加速度、タッチダイナミクス
- アンチ検出ハニーポット — ランダム化されたCSSクローキング、デコイフィールド、現実的なフィールド名
- サーバーサイド改ざん検出 — シグナルの整合性を検証、ゲーミング試行を検出
- リクエストフィンガープリントバインディング — PoWトークンをHTTPリクエスト属性にバインド
- レート制限 — すべての検証エンドポイントに対するセッション単位のレート制限
- No-script検出 — 検出ペイロードを送信しないクライアントを識別
- 既知のクローラーの許可リスト — スコアリングから除外される20以上の正当なボット
アーキテクチャ
Browser Your Server
┌──────────────────────────┐ ┌──────────────────────┐
│ Collector (singleton) │ POST │ Express Middleware │
│ ├─ 28 detection modules│ signals │ ├─ NonceManager │
│ ├─ BehaviorTracker │ + nonce │ ├─ RateLimiter │
│ ├─ HoneypotTraps │───────────▶│ ├─ TamperDetector │
│ ├─ Stack trace traps │ │ ├─ computeVerdict() │
│ └─ IframeContext │ │ └─ Proof-of-Work │
│ │ verdict │ │
│ ↓ collect() → │ + proof │ Returns: │
│ DetectionResult[] │◀───────────│ { verdict, score, │
└──────────────────────────┘ │ confidence, proof, │
│ tamperScore } │
└──────────────────────┘
│
▼
Session-gated endpoint
(login, checkout, etc.)
validates proof before
granting access
主要な原則: ブラウザは生の DetectionResult[] シグナルのみを収集します。サーバーが秘密の重みテーブルを使用して最終判定を計算します。クライアントで計算された判定は決して信頼されません。
クイックスタート
1. ビルド
npm install
npm run build
dist/ に出力:
botdetect.min.js (ポリフィル付き, ~151 KB)
botdetect-clean.min.js (最新ブラウザのみ, ~74 KB)
2. ページに組み込む
<script src="/path/to/botdetect.min.js"></script>
<script>
BotDetect.collector.enableTraps();
BotDetect.collector.enableBehavioralTracking();
BotDetect.collector.enableHoneypots();
</script>
3. サーバーサイド検証を設定
cd server
npm install express cors express-session
node example-integration.js
4. 機密アクションでシグナルを送信
async function onLogin() {
const { nonce } = await (await fetch('/api/botdetect/nonce')).json();
BotDetect.collector.setNonce(nonce);
const signals = await BotDetect.collector.collect();
const resp = await fetch('/api/botdetect/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ signals, nonce })
});
const { verdict, score, proof, friction } = await resp.json();
document.getElementById('botdetect-proof').value = proof;
document.getElementById('login-form').submit();
}
5. サーバーで検証
app.post('/api/login', (req, res) => {
const bd = req.session.botdetect;
if (!bd) return res.status(403).json({ error: 'no_verification' });
if (bd.verdict === 'bot') return res.status(403).json({ error: 'access_denied' });
if (bd.verdict === 'suspicious') return challengeCaptcha(req, res);
res.json({ success: true });
});
クライアントサイドAPI
コレクター(シングルトン)
import Collector from './collector/Collector';
// またはグローバル: BotDetect.collector
検出器(デバッグのみ)
import Detector from './detector/Detector';
警告: analyze() はブラウザ内で完全に実行されます。本番環境の判断にその出力を使用しないでください。
型定義
interface DetectionResult {
name: string; // Module name
score: number; // 0.0 – 1.0
weight: number; // 1 – 10 (importance)
detail?: string; // Human-readable description
}
interface DetectionVerdict {
verdict: 'bot' | 'suspicious' | 'human';
score: number; // 0.0 – 1.0
confidence: number; // 0.0 – 1.0
signals: DetectionResult[];
threshold: number;
friction: 'monitor' | 'challenge' | 'block';
}
interface CollectorConfig {
detectionTimeoutMs: number; // per-module timeout (default: 3000)
enableTraps: boolean;
enableBehavioralTracking: boolean;
enableHoneypots: boolean;
thresholds: { strict: number; balanced: number; relaxed: number };
}
サーバーサイド統合
Express ミドルウェア
const { createBotDetectEndpoint } = require('./server');
const { router, generateProofOfWork, cleanup } = createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT,
scoring: {
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
},
nonce: { ttl: 300000 }, // 5-minute nonce expiry
noScript: { timeout: 10000 }, // 10s no-script window
rateLimit: { maxRequests: 10, windowMs: 60000 },
noScriptPaths: ['/api/login', '/api/checkout', '/api/register']
});
app.use('/api', router);
エンドポイント
| エンドポイント | メソッド | 目的 |
|---|
/api/botdetect/nonce | GET | 使い捨てnonceを発行 |
|
サーバーレスポンス形式
{
"verdict": "human",
"score": 0.125,
"confidence": 0.85,
"tamperScore": 0,
"friction": "monitor",
"threshold": 0.5,
"proof": "a1b2c3d4e5f6..."
}
サーバーサイドスコアリング(Node.js)
const { computeVerdict, RateLimiter, NonceManager } = require('./scoring');
const verdict = computeVerdict(signals, {
threshold: 'balanced',
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
});
// verdict.tamperScore > 0 if signal tampering detected
検出モジュール
自動化フレームワーク(重み 5–7)
Playwright固有(重み 3–4)
| モジュール | 検出対象 | 重み |
|---|
playwrightWebKit | WebKit自動化成果物 | 4 |
playwrightOrientation | 方位 + chrome.runtime の不整合 | 3 |
行動分析(重み 7)
| モジュール | 分析対象シグナル | 重み |
|---|
behavioralAnalysis | マウスの曲線 + 直線比率、キーストロークCV + バーストパターン + KPM、スクロール加速度 + 方向変化、タッチ力の分散 + 半径 | 7 |
ブラウザフィンガープリンティング(重み 3–4)
Navigator & OS プロパティ(重み 5)
| モジュール | チェック内容 | 重み |
|---|
navigatorInconsistencies | 11項目: languages、plugins、mimeTypes、platform、UA、cookies、DNT、touch、hardwareConcurrency、deviceMemory、connection | 5 |
アクティブトラップ & ハニーポット(重み 8–9)
| モジュール | 検出対象 | 重み |
|---|
honeypotTraps | ランダム化された隠しフィールド + デコイ + カナリアエンドポイント | 9 |
stackTraceTraps |
ネットワーク & コンテキスト(重み 1–2)
許可リスト(重み 0)
| モジュール | 検出対象 | 重み |
|---|
verifiedBots | 20以上の既知クローラー(Googlebot、Bingbot、Yandex、Facebook、Twitter等)— -1を返し、スコアリングから除外 | 0 |
設定
コレクター
const collector = Collector.getInstance({
detectionTimeoutMs: 1000, // UX向上のため低く設定
enableTraps: true,
enableBehavioralTracking: true,
enableHoneypots: true,
thresholds: {
strict: 0.3, // 積極的(ログイン、チェックアウト)
balanced: 0.5, // デフォルト
relaxed: 0.7 // 寛容(コンテンツブラウジング)
}
});
検出器(デバッグのみ)
const detector = Detector.getInstance({
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2, // ブースト前の最小シグナル数
signalBoostThreshold: 0.8, // この閾値以上のシグナルに追加重み
failPolicy: 'open', // 'open' = エラー時 human, 'closed' = エラー時 bot
frictionThresholds: {
monitor: 0.2,
challenge: 0.5,
block: 0.8
}
});
サーバー
createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT, // 秘密に保持
scoring: { threshold: 'balanced' },
nonce: { ttl: 300000, cleanupInterval: 60000 },
noScript: { timeout: 10000 },
rateLimit: { maxRequests: 10, windowMs: 60000 },
requestFingerprint: true, // PoWをリクエスト属性にバインド
noScriptPaths: ['/api/login', '/api/checkout']
});
本番環境チェックリスト
セキュリティ
パフォーマンス
モニタリング
テスト
npm test # 6スイート74のJestテスト
npm run typecheck # TypeScript strictモード
npm run lint # ESLint
npm run build # Webpackプロダクションバンドル
ライセンス
Apache — Lahmeri Mohamed Amine