APIの不正利用は、サービスの安定性・コスト・セキュリティを直撃する。Claude Codeを使ってリスクスコアリングから自動ブロックまでを設計する実践ガイド。
リスクスコアリング:0〜100の数値で脅威を定量化
API不正利用検知の核心は「リスクスコア」。0〜100のスコアを算出し、閾値に応じてアクションを変える。
スコア 0〜29 : 正常
スコア 30〜69 : 要注意 → CAPTCHAチャレンジ
スコア 70〜100: 高リスク → 自動ブロック
Claude Codeへのプロンプト例:
以下の5パターンをもとにリスクスコア計算関数を実装してください。
各パターンの重みを設定し、合計が100を超えないようにしてください。
5つの検知パターン
1. 認証失敗率(Fail Rate)
// 直近10分の認証失敗率
const failRate = failCount / totalRequests;
const score1 = Math.min(failRate * 100, 30); // 最大30点
失敗率30%超えで最大スコアに達する。ブルートフォース攻撃の典型パターン。
2. リクエストレート(Request Rate)
// 1分あたりのリクエスト数
const rpm = requestCount / windowMinutes;
// 正常ユーザーは通常60rpm以下
const score2 = Math.min(Math.max(0, rpm - 60) / 40 * 25, 25); // 最大25点
100rpmを超えたあたりから自動化を疑う閾値設定が有効。
3. エンドポイント多様性(Endpoint Diversity)
// 短時間で多数の異なるエンドポイントを叩いているか
const uniqueEndpoints = new Set(recentRequests.map(r => r.path)).size;
const score3 = Math.min(uniqueEndpoints / 20 * 20, 20); // 最大20点
スキャナーは網羅的にエンドポイントを探索する。多様性が高いほど怪しい。
4. アカウントのマルチIP(Multi-IP per Account)
// 同一アカウントが複数IPから操作
const uniqueIPs = await getUniqueIPsForAccount(accountId, '1h');
const score4 = Math.min((uniqueIPs - 1) * 5, 15); // 最大15点
1アカウントが短時間で3IP以上から接続 → クレデンシャルスタッフィングの疑い。
5. ヘッドレスUA(Headless UA Detection)
// HeadlessChrome / Puppeteer / Selenium のシグネチャ検出
const headlessPatterns = [
/HeadlessChrome/i,
/PhantomJS/i,
/Selenium/i,
/webdriver/i
];
const isHeadless = headlessPatterns.some(p => p.test(userAgent));
const score5 = isHeadless ? 10 : 0; // 最大10点
ボットタイミング検出:変動係数(CV)の活用
人間の操作には自然なばらつきがある。ボットのリクエスト間隔は機械的に均一になりがち。
function calculateCV(intervals) {
const mean = intervals.reduce((a, b) => a + b) / intervals.length;
const variance = intervals.reduce((sum, x) => sum + Math.pow(x - mean, 2), 0) / intervals.length;
const stdDev = Math.sqrt(variance);
return stdDev / mean; // 変動係数
}
// CV < 0.1 は機械的すぎる(人間なら通常0.3以上)
const cv = calculateCV(requestIntervals);
if (cv < 0.1 && intervals.length >= 10) {
riskScore += 15; // ボットタイミングペナルティ
}
CVが低いほど均一 = ボットの可能性が高い。Claude Codeでこのロジックを実装する際、「正規分布のシミュレーションでCVの閾値を検証して」と指示すると適切な閾値が導き出せる。
RedisパイプラインでのAPI記録
リアルタイム検知にはRedisのパイプラインが必須。1リクエストあたりのレイテンシを最小化しながら複数のカウンターを更新する。
async function recordApiRequest(ctx) {
const { ip, accountId, path, statusCode, userAgent, responseTime } = ctx;
const now = Date.now();
const windowKey = Math.floor(now / 60000); // 1分ウィンドウ
const pipeline = redis.pipeline();
// IPベースのカウンター(TTL: 10分)
pipeline.hincrby(`ip:${ip}:${windowKey}`, 'total', 1);
pipeline.expire(`ip:${ip}:${windowKey}`, 600);
if (statusCode >= 400) {
pipeline.hincrby(`ip:${ip}:${windowKey}`, 'fail', 1);
}
// エンドポイント記録
pipeline.sadd(`ip:${ip}:endpoints:${windowKey}`, path);
pipeline.expire(`ip:${ip}:endpoints:${windowKey}`, 600);
// アカウントIPセット
if (accountId) {
pipeline.sadd(`account:${accountId}:ips`, ip);
pipeline.expire(`account:${accountId}:ips`, 3600);
}
// リクエスト間隔記録(タイミング分析用)
pipeline.lpush(`ip:${ip}:intervals`, now);
pipeline.ltrim(`ip:${ip}:intervals`, 0, 99); // 最新100件
pipeline.expire(`ip:${ip}:intervals`, 600);
await pipeline.exec();
}
パイプラインにより、1回のネットワーク往復で全カウンターを更新できる。
自動ブロックの実装
async function enforceRiskScore(ip, score) {
if (score >= 70) {
// 自動ブロック:15分間
await redis.setex(`blocked:${ip}`, 900, score.toString());
await notifySlack(`🚨 IP ${ip} blocked (score: ${score})`);
return { action: 'block', retryAfter: 900 };
}
if (score >= 30) {
// CAPTCHAチャレンジ
return { action: 'captcha', score };
}
return { action: 'allow', score };
}
// Expressミドルウェアとして組み込む
app.use(async (req, res, next) => {
const ip = req.ip;
// ブロックリストチェック
const blocked = await redis.get(`blocked:${ip}`);
if (blocked) {
return res.status(429).json({
error: 'Too Many Requests',
retryAfter: await redis.ttl(`blocked:${ip}`)
});
}
const score = await calculateRiskScore(ip, req);
const enforcement = await enforceRiskScore(ip, score);
if (enforcement.action === 'block') {
return res.status(429).json({ error: 'Blocked', score });
}
req.riskScore = score;
next();
});
まとめ
- リスクスコアは定量化が命 — 感覚でなく数値で判断することで、誤検知と見逃しのバランスを調整できる
- 5パターンの組み合わせで精度向上 — 単一指標では誤検知が多い。複合スコアで精度を高める
- CVによるタイミング分析 — ボットと人間を区別する強力な指標。従来のUA/IP判定を補完する
- Redisパイプラインで低レイテンシ — 検知処理がAPIのボトルネックにならないよう、パイプラインで一括更新
Claude Codeを使えば、これらのロジックを「脅威パターンを定義してスコアリング関数を実装して」という自然言語指示で素早くプロトタイプできる。セキュリティ設計のたたき台として活用してほしい。
Security Pack(¥1,480) — OWASP準拠のAPIセキュリティプロンプト集。不正利用検知・認証設計・脆弱性チェックリストをセットで収録。
PromptWorksで見る
Top comments (0)