APIサーバーにおいて、外部からの過剰なリクエストによってリソースが枯渇する事態は珍しくありません。特にNode.jsのように非同期で高速にリクエストを処理できる環境では、同時接続数や負荷に対する防御策が欠かせません。
本記事では、Expressフレームワークを用いて、Rate Limiter(レート制限)を中間処理として実装し、大量アクセスに対する防御力を高める手法を解説します。
なぜRate Limiterが必要なのか
以下のような状況でRate Limiterの導入が有効です。
- 短時間に特定IPから大量アクセスが発生
- BotによるAPIスパム攻撃やDoSの初期防衛
- ユーザーごとのAPI使用制限(無料枠制限など)
レートリミットは、アプリケーション層で実装でき、軽量なミドルウェアとして機能します。
express-rate-limitの導入
最も手軽な実装は、express-rate-limit
というパッケージを使う方法です。
npm install express-rate-limit
続いて、以下のようにミドルウェアとして設定します。
const express = require('express');
const rateLimit = require('express-rate-limit');
const app = express();
// レートリミッターの設定
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1分間
max: 100, // 1分間に最大100件
standardHeaders: true,
legacyHeaders: false,
message: 'リクエストが多すぎます。しばらくしてから再試行してください。'
});
// 全てのルートに適用
app.use(limiter);
app.get('/', (req, res) => {
res.send('正常アクセス');
});
app.listen(3000, () => {
console.log('サーバー起動中');
});
上記の例では、「1分間に100リクエスト」までを許容し、それを超えた場合はHTTP 429エラーを返します。
特定ルートのみ制限をかける
ログインや検索など、負荷が高い特定のエンドポイントだけに適用することも可能です。
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分
max: 5, // 最大5回の試行
message: 'ログイン試行が多すぎます。15分後に再試行してください。'
});
app.post('/login', loginLimiter, (req, res) => {
// ログイン処理
});
これにより、ログインフォームの不正連打(ブルートフォース攻撃)を防ぐことができます。
IPアドレス単位で制限される仕組み
デフォルトでは、クライアントのIPアドレスを識別して制限をかけます。プロキシやCDN環境ではtrust proxy
設定が必要です。
app.set('trust proxy', 1); // Heroku, Vercelなどを使用する場合
Redisなどを活用した永続化
デフォルトでは、メモリ上でカウントが管理されるため、プロセス再起動でリセットされます。Redisなどのストアと連携することで、スケーラブルな環境に対応可能です。
たとえば、rate-limit-redis
との併用で以下のような構成が可能です:
npm install rate-limit-redis ioredis
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');
const redisClient = new Redis();
const limiter = rateLimit({
store: new RedisStore({
sendCommand: (...args) => redisClient.call(...args)
}),
windowMs: 1 * 60 * 1000,
max: 100,
});
まとめ|Expressにおける防御の第一歩として
Node.js + Express で運用するAPIにおいて、Rate Limiterの導入はセキュリティ対策とリソース保護の両面で非常に有効です。
簡易な実装で導入可能でありながら、大量アクセスへの初期防衛策として高い効果を発揮します。Redisとの併用でクラスタ環境にも対応可能です。
今後、認証・APIキー・ログ集計と組み合わせた、より高度な利用制限を実現する土台としても活用できます。