サイトのAPI図鑑B版
掲載情報が正確でない可能性があります。
セキュリティ・コンプライアンス

APIレート制限とDDoS対策の実装ガイド【Redis・Cloudflare・WAF】

APIのレート制限(Token Bucket・Sliding Window)の実装方法と、Cloudflare・AWS WAF・NGINXを使ったDDoS攻撃対策・IP制限・ボット対策の設定を解説します。

#レート制限#DDoS対策#WAF#Cloudflare

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アルゴリズムはシンプルかつ効果的な選択です。

よくある質問

Q.Token BucketとSliding Window Counterのレート制限はどう違いますか?

Token Bucketはバケツにトークンを溜めておき、リクエストごとに使う方式です。バースト(瞬間的に多くのリクエスト)を許容しながら長期的な平均レートを制限できます。Sliding Window Counterは指定した時間窓の中のリクエスト数をカウントし、より均一なレート制限を実現します。

Q.CloudflareのレートリミティングとNGINXのlimit_reqはどちらが良いですか?

Cloudflareのレート制限はグローバルのエッジで適用されるため、悪意のあるトラフィックがオリジンサーバーに到達する前にブロックできます。NGINXのlimit_reqはオリジンサーバーで処理されるため、攻撃トラフィック自体はサーバーに届きます。大規模DDoS対策にはCloudflare、細かい制御にはNGINXが向いています。

Q.正規のユーザーがレート制限に引っかかった場合のユーザー体験は?

レート制限に引っかかった場合は429 Too Many Requestsを返し、Retry-AfterヘッダーにAPIを再度呼び出せるまでの時間を秒単位で返すことが推奨されます。ユーザー向けのエラーメッセージに「しばらくお待ちください」と表示することでUXへの影響を和らげます。

関連記事