APIレート制限の重要性
レート制限はAPIの可用性・公平性・セキュリティを守るための必須機能です。悪意のあるスクレイパー・DDoS攻撃・バグのあるクライアントからAPIを守りながら、正規のユーザーには適切なリソースを保証します。
Redisを使ったSliding Window Counterの実装
import { createClient } from 'redis';
const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
const rateLimiter = async (identifier, limit, windowSeconds) => {
const now = Date.now();
const windowStart = now - windowSeconds * 1000;
const key = `ratelimit:${identifier}`;
// Redisのパイプラインでアトミックに処理
const pipe = redis.multi();
pipe.zRemRangeByScore(key, '-inf', windowStart); // 古いエントリを削除
pipe.zAdd(key, { score: now, value: now.toString() });
pipe.zCard(key); // 現在のカウント
pipe.expire(key, windowSeconds);
const results = await pipe.exec();
const count = results[2] as number;
return {
allowed: count <= limit,
count,
limit,
remaining: Math.max(0, limit - count)
};
};
// ミドルウェアとして使用
const rateLimitMiddleware = (limit, windowSeconds) => async (req, res, next) => {
const identifier = req.user?.id || req.ip;
const { allowed, remaining, limit: lim } = await rateLimiter(
identifier, limit, windowSeconds
);
res.set({
'X-RateLimit-Limit': lim,
'X-RateLimit-Remaining': remaining,
'X-RateLimit-Reset': Math.ceil(Date.now() / 1000) + windowSeconds
});
if (!allowed) {
return res.status(429).json({
error: 'Too Many Requests',
retryAfter: windowSeconds
});
}
next();
};
CloudflareのレートリミティングルールAPI経由での設定
// Cloudflare Rate Limiting RuleをAPIで設定
const createRateLimitRule = async (zoneId) => {
const response = await fetch(
`https://api.cloudflare.com/client/v4/zones/${zoneId}/rate_limits`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${CLOUDFLARE_API_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
match: {
request: {
methods: ['GET', 'POST', 'PUT', 'DELETE'],
url_pattern: 'api.example.com/api/*'
},
response: { status: [200, 201, 400, 401, 403, 404, 429] }
},
period: 60, // 60秒の時間窓
threshold: 100, // 100リクエスト
action: {
mode: 'ban', // 超過時にBANを適用
timeout: 300 // 5分間ブロック
}
})
}
);
return response.json();
};
NGINXのDDoS対策設定
# nginx.confのレート制限・DDoS対策設定
http {
# リクエストレート制限ゾーンの定義
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $http_x_api_key zone=apikey_limit:10m rate=100r/m;
# 接続数制限
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
# 大きすぎるリクエストボディを拒否
client_max_body_size 10m;
# スローヘッダー攻撃対策
client_header_timeout 10s;
client_body_timeout 10s;
}
}
}
IP・地域ブロックの実装
// 特定のIPレンジやCIDRをブロック
const BLOCKED_IPS = new Set(['192.0.2.0/24', '198.51.100.1']);
app.use((req, res, next) => {
const clientIp = req.headers['cf-connecting-ip'] || // Cloudflare経由
req.headers['x-forwarded-for']?.split(',')[0] ||
req.ip;
if (isBlocked(clientIp, BLOCKED_IPS)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
});
まとめ
レート制限とDDoS対策は多層防御で実装することが重要です。Cloudflare等のCDN・WAFレイヤーで大規模な攻撃を吸収し、NGINXでオリジン保護、アプリケーションレイヤーでAPIキー・ユーザーごとの細かい制御を実装します。Redisを使ったSliding Windowアルゴリズムはシンプルかつ効果的な選択です。