APIレート制限:アルゴリズムと実装

Security2026-09-20TryQuickToolBox

あなたのAPIが攻撃を受けています。高度なハッカーによるものではなく、毎秒何千回もエンドポイントを叩き、リソースを消費し、正規ユーザーのサービスを低下させる単純なスクリプトによるものです。レート制限がなければ、1つの問題のあるクライアントがアプリケーション全体をダウンさせる可能性があります。このガイドでは、コアアルゴリズムを説明し、Node.jsとNginxでの実用的な実装を示してAPIを保護します。

レート制限が重要な理由

レート制限は、クライアントが一定の時間枠内で行えるリクエスト数を制御します。これは以下に対する最初の防御線です:

セキュリティ以外にも、レート制限は公平な使用を保証し、段階的な価格プランなどのビジネスルールを適用するのに役立ちます。

レート制限アルゴリズム

APIレート制限では4つのアルゴリズムが主流です。それぞれ精度、メモリ使用量、バースト処理にトレードオフがあります。

1. 固定ウィンドウ

固定された時間間隔(例:1分あたり100リクエスト)でリクエストをカウントします。ウィンドウがリセットされるとカウンタもリセットされます。

2. スライディングウィンドウ

各リクエストのタイムスタンプを追跡し、直近N秒以内にいくつあるかをカウントします。これによりバーストが平滑化されます。

3. トークンバケット

バケットにトークンが入っています。トークンは固定レートで追加されます。各リクエストは1つのトークンを消費します。バケットが空の場合、リクエストは拒否されます。

4. リーキーバケット

リクエストはキュー(バケット)に入り、一定レートで処理されます。キューが満杯の場合、リクエストは破棄されます。

アルゴリズムバースト処理メモリユースケース
固定ウィンドウ不良低シンプルなAPI
スライディングウィンドウ良好中汎用
トークンバケット優秀中バースト許容のあるAPI
リーキーバケットなし中トラフィックの平滑化

Node.jsでのレート制限の実装

ExpressとRedisを使用して、分散状態のためのトークンバケットレートリミッタを実装します。複数のサーバーインスタンスがある場合、Redisは不可欠です。

ステップ1:依存関係のインストール

npm install express redis

ステップ2:レートリミッタミドルウェアの作成

const redis = require('redis');
const client = redis.createClient();

async function tokenBucketLimiter(req, res, next) {
  const key = `rate_limit:${req.ip}`;
  const capacity = 10; // max tokens
  const refillRate = 1; // tokens per second

  const now = Date.now();
  const data = await client.hGetAll(key);
  let tokens = data.tokens ? parseFloat(data.tokens) : capacity;
  let lastRefill = data.lastRefill ? parseInt(data.lastRefill) : now;

  // Refill tokens based on elapsed time
  const elapsed = (now - lastRefill) / 1000;
  tokens = Math.min(capacity, tokens + elapsed * refillRate);

  if (tokens < 1) {
    return res.status(429).json({ error: 'Too many requests' });
  }

  tokens -= 1;
  await client.hSet(key, {
    tokens: tokens.toString(),
    lastRefill: now.toString()
  });
  await client.expire(key, 60); // auto-cleanup

  next();
}

app.use(tokenBucketLimiter);

このミドルウェアはトークン数をアトミックにチェックして更新します。本番環境では、競合状態を避けるためにRedisトランザクションまたはLuaスクリプトを使用してください。

Nginxでのレート制限の実装

Nginxはlimit_reqモジュールによる組み込みのレート制限を提供します。これはリーキーバケットアルゴリズムを使用します。

ステップ1:レート制限ゾーンの定義

nginx.confのhttpブロック内:

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

これにより、IPごとに毎秒10リクエストを許可する10MBのゾーンapiが作成されます。

ステップ2:制限の適用

locationブロック内:

location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://backend;
}

burst=20は最大20リクエストの短いバーストを許可します。nodelayはバーストリクエストをキューに入れずに即座に処理します。

APIレート制限のベストプラクティス

FAQ

レート制限とスロットリングの違いは何ですか?

レート制限はしきい値を超えたリクエストをブロックしますが、スロットリングはそれらを遅くします(例:キューに入れるか遅延させる)。レート制限は二値的で、スロットリングは段階的です。

どのレート制限アルゴリズムを使用すべきですか?

ほとんどのAPIでは、トークンバケットが良いバランスを提供します:バーストを許可しつつ平均レートを強制します。厳密な平滑化が必要な場合はリーキーバケットを使用してください。シンプルさを求めるなら、固定ウィンドウは低トラフィックのAPIに適しています。

認証済みユーザーと匿名ユーザーのレート制限をどう扱いますか?

匿名ユーザーにはより厳しい制限(例:IPごと)を適用し、認証済みユーザーにはより寛大な制限(例:APIキーごと)を適用します。サブスクリプションプランに基づく段階的な制限を実装することもできます。

APIトラフィックを分析する準備はできましたか?Nginx Log Analyzerを使用してログを解析し、レート制限違反を発見し、しきい値を最適化しましょう。