rate-limiting-abuse-protection について
rate-limiting-abuse-protectionは、過剰なリクエストや不正利用からAPIを保護する開発者向けのスキルです。複数の制限方式と、ユーザー、IP、Redisの状態を使った実装方法を紹介します。
主な機能
- 01固定ウィンドウやスライディングウィンドウなどの方式
- 02Expressのレート制限ミドルウェア例
- 03Redisによる制限チェック
- 04ユーザーまたはIP単位のリクエスト制限
- 05レート制限レスポンスヘッダーの返却
活用シーン
- 01APIエンドポイントごとのリクエスト制限
- 02ユーザーごとのリクエスト枠の設定
- 03不審なIPのブロックと違反記録
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill rate-limiting-abuse-protectionインストール後、Claude Code で/rate-limiting-abuse-protectionを入力して読み込まれたか確認します。
詳細
レート制限と不正利用対策
インテリジェントなレート制限で、API を不正利用から保護します。
レート制限の戦略
固定ウィンドウ:1 時間あたり 100 リクエスト スライディングウィンドウ:より正確で、バーストを防止します トークンバケット:上限までのバーストを許可します リーキーバケット:リクエストレートを平滑化します
実装(Express)
import rateLimit from "express-rate-limit";
// Global rate limit
const globalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: "Too many requests, please try again later",
standardHeaders: true, // Return rate limit info in headers
legacyHeaders: false,
});
// Stricter limit for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Only 5 attempts
skipSuccessfulRequests: true, // Don't count successful logins
});
app.use("/api/", globalLimiter);
app.use("/api/auth/login", authLimiter);
Redis ベースのレート制限
import Redis from "ioredis";
const redis = new Redis();
export const checkRateLimit = async (
key: string,
max: number,
window: number
): Promise<{ allowed: boolean; remaining: number }> => {
const now = Date.now();
const windowStart = now - window;
await redis
.multi()
.zremrangebyscore(key, 0, windowStart)
.zadd(key, now, `${now}`)
.zcard(key)
.expire(key, Math.ceil(window / 1000))
.exec();
const count = await redis.zcard(key);
return {
allowed: count <= max,
remaining: Math.max(0, max - count),
};
};
ユーザーごとのレート制限
export const userRateLimit = (max: number, window: number) => {
return async (req, res, next) => {
if (!req.user) return next();
const key = `rate_limit:user:${req.user.id}`;
const result = await checkRateLimit(key, max, window);
res.setHeader("X-RateLimit-Limit", max);
res.setHeader("X-RateLimit-Remaining", result.remaining);
if (!result.allowed) {
return res.status(429).json({
error: "Rate limit exceeded",
retryAfter: window / 1000,
});
}
next();
};
};
IP ベースの保護
// Block suspicious IPs
const ipBlocklist = new Set<string>();
export const checkIPReputation = async (ip: string): Promise<boolean> => {
if (ipBlocklist.has(ip)) return false;
// Check against threat intelligence API
const reputation = await checkThreatIntel(ip);
if (reputation.isMalicious) {
ipBlocklist.add(ip);
return false;
}
return true;
};
レスポンスヘッダー
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
Retry-After: 3600
ベストプラクティス
- エンドポイントごとに異なる制限を設定する
- 負荷の高い操作には、より低い制限を設定する
- 内部サービスにはレート制限を適用しない
- 有用なエラーメッセージを返す
- レート制限違反をログに記録する
- 不正利用のパターンを監視する
- 信頼できる IP を許可リストに追加する
出力チェックリスト
- レートリミッターミドルウェア
- ルートごとのポリシー
- ユーザーベースの制限
- IP ベースの制限
- レート制限ヘッダー
- 安全なエラーレスポンス
- 可観測性/ログ記録
- 内部サービス向けのバイパス
コメント
Markdown 対応