express-rate-limit vs rate-limiter-flexible vs express-slow-down vs express-limiter vs express-brute
Express.js アプリケーションにおけるレート制限パッケージの比較
express-rate-limitrate-limiter-flexibleexpress-slow-downexpress-limiterexpress-brute類似パッケージ:

Express.js アプリケーションにおけるレート制限パッケージの比較

express-bruteexpress-limiterexpress-rate-limitexpress-slow-downrate-limiter-flexible は、すべて Express.js アプリケーションでレート制限(アクセス制限)を実装するためのミドルウェアパッケージです。これらは API エンドポイントへの過剰なリクエストを防ぎ、DDoS 攻撃やブルートフォース攻撃からアプリケーションを保護します。express-rate-limit が最も広く採用されており、rate-limiter-flexible は柔軟なストア対応が特徴です。express-slow-down はリクエストをブロックせず速度を落とすアプローチを取ります。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
express-rate-limit22,817,2453,231141 kB84ヶ月前MIT
rate-limiter-flexible1,774,6673,484198 kB1525日前ISC
express-slow-down79,08229938.2 kB44ヶ月前MIT
express-limiter21,652423-218年前MIT
express-brute17,307568-219年前BSD

Express.js レート制限パッケージ:技術比較と実装ガイド

Express.js アプリケーションで API 保護を実装する際、適切なレート制限パッケージの選択はセキュリティとパフォーマンスに直結します。express-bruteexpress-limiterexpress-rate-limitexpress-slow-downrate-limiter-flexible の 5 つのパッケージは、それぞれ異なるアプローチと特徴を持っています。実務での選択基準を明確にするために、技術的な違いを深掘りします。

📦 パッケージの現状とメンテナンス状態

express-brute は 2015 年頃から存在する古いパッケージで、現在はアクティブなメンテナンスが行われていません。

// express-brute: 古い API スタイル
const ExpressBrute = require('express-brute');
const store = new ExpressBrute.MemoryStore();
const bruteforce = new ExpressBrute(store);

app.post('/login', bruteforce.prevent, loginHandler);

express-limiter も同様に更新が停滞しており、Redis 特化型の制限ミドルウェアです。

// express-limiter: Redis 必須
const expressLimiter = require('express-limiter');
const redis = require('redis');
const client = redis.createClient();

expressLimiter(app, client, {
  lookup: 'connection.remoteAddress',
  total: 100,
  expire: 1000 * 60 * 60
});

express-rate-limit は現在もアクティブにメンテナンスされており、npm で最もダウンロードされています。

// express-rate-limit: 現代的な API
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  message: 'リクエストが多すぎます'
});

app.use('/api/', limiter);

express-slow-downexpress-rate-limit の作者によって作成され、同じエコシステムで動作します。

// express-slow-down: 遅延による制限
const slowDown = require('express-slow-down');

const speedLimiter = slowDown({
  windowMs: 15 * 60 * 1000,
  delayAfter: 50,
  delayMs: 500
});

app.use('/api/', speedLimiter);

rate-limiter-flexible は最新の設計で、複数のストレージバックエンドを公式にサポートしています。

// rate-limiter-flexible: 柔軟なストア対応
const { RateLimiterRedis } = require('rate-limiter-flexible');

const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 10,
  duration: 1
});

app.use('/api/', (req, res, next) => {
  rateLimiter.consume(req.ip)
    .then(() => next())
    .catch(() => res.status(429).send('制限超過');
});

🔧 ストレージバックエンドの対応状況

ストレージ選択は、アプリケーションのスケールに直接影響します。

パッケージメモリRedisMongoDBMemcachedその他
express-bruteカスタムストア可能
express-limiterRedis のみ
express-rate-limit公式ストア多数
express-slow-downexpress-rate-limit と共通
rate-limiter-flexible15+ ストア対応

express-rate-limit のストア設定例:

const RedisStore = require('rate-limit-redis');
const { createClient } = require('redis');

const limiter = rateLimit({
  store: new RedisStore({
    sendCommand: (...args) => redisClient.sendCommand(args)
  }),
  windowMs: 15 * 60 * 1000,
  max: 100
});

rate-limiter-flexible のストア設定例:

const { RateLimiterMongo } = require('rate-limiter-flexible');
const { MongoClient } = require('mongodb');

const rateLimiter = new RateLimiterMongo({
  storeClient: mongoClient,
  tableName: 'rateLimits',
  points: 10,
  duration: 1
});

🎯 制限ロジックの実装アプローチ

各パッケージは異なる方法でリクエストをカウントし、制限を適用します。

express-brute は失敗カウントに特化しており、ログイン試行などのブルートフォース対策に適しています。

// express-brute: 失敗時のみカウント
bruteforce.handleFailures((req, res, next, nextValidRequestDate) => {
  if (req.body.username === 'admin') {
    return res.status(403).send('アカウントロック中');
  }
  next();
});

express-limiter は単純なカウントベースで、Redis の TTL 機能を利用します。

// express-limiter: シンプルカウント
expressLimiter(app, client, {
  lookup: 'headers.api-key',
  total: 1000,
  expire: 1000 * 60 * 60,
  onRateLimited: (req, res) => {
    res.status(429).send('レート制限超過');
  }
});

express-rate-limit は柔軟なキー生成とカスタムメッセージをサポートします。

// express-rate-limit: カスタムキー生成
const limiter = rateLimit({
  keyGenerator: (req) => {
    return req.user?.id || req.ip;
  },
  handler: (req, res) => {
    res.status(429).json({
      error: '制限超過',
      retryAfter: Math.ceil(res.get('Retry-After'))
    });
  }
});

express-slow-down はブロックではなく遅延を適用します。

// express-slow-down: 段階的遅延
const speedLimiter = slowDown({
  delayAfter: 50,
  delayMs: (hits) => Math.min(hits * 100, 60000),
  skipFailedRequests: true
});

rate-limiter-flexible はポイントベースのシステムで、異なるアクションに異なるコストを設定できます。

// rate-limiter-flexible: ポイントベース
const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 100,
  duration: 60
});

// 重い操作は更多ポイント消費
await rateLimiter.consume(userId, 5); // 5 ポイント消費

⚠️ エラーハンドリングとレスポンス

制限超過時のレスポンス制御は、ユーザー体験に影響します。

express-brute はカスタムエラーハンドラを登録します:

bruteforce.getMiddleware({
  onBlocked: (req, res, next, nextValidRequestDate) => {
    res.status(429).json({
      error: '一時的にブロックされています',
      retryAfter: nextValidRequestDate
    });
  }
});

express-rate-limit は標準 HTTP ヘッダーを自動設定します:

// 自動設定されるヘッダー
// X-RateLimit-Limit: 100
// X-RateLimit-Remaining: 95
// X-RateLimit-Reset: 1640000000
// Retry-After: 60

rate-limiter-flexible は詳細な制限情報を返します:

try {
  const response = await rateLimiter.consume(key);
  res.set('Retry-After', Math.ceil(response.msBeforeNext / 1000));
  next();
} catch (rej) {
  res.set('Retry-After', Math.ceil(rej.msBeforeNext / 1000));
  res.status(429).json({
    pointsRemaining: rej.remainingPoints,
    msBeforeNext: rej.msBeforeNext
  });
}

🏗️ 実運用での選択基準

小規模プロジェクト(メモリストアで十分)

推奨:express-rate-limit

設定がシンプルで、デフォルトのメモリストアでも十分な場合:

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  standardHeaders: true,
  legacyHeaders: false
});

app.use('/api/', limiter);

中規模プロジェクト(Redis 必要)

推奨:express-rate-limit または rate-limiter-flexible

複数サーバー環境で Redis を使用する場合:

// express-rate-limit + Redis
const limiter = rateLimit({
  store: new RedisStore({ sendCommand: redisClient.sendCommand }),
  windowMs: 15 * 60 * 1000,
  max: 100
});

// rate-limiter-flexible + Redis
const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 100,
  duration: 900
});

大規模プロジェクト(複雑な制限ロジック)

推奨:rate-limiter-flexible

異なるエンドポイントで異なる制限を適用する場合:

const loginLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 5,
  duration: 300
});

const apiLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 1000,
  duration: 3600
});

app.post('/login', async (req, res, next) => {
  try {
    await loginLimiter.consume(req.ip);
    next();
  } catch {
    res.status(429).send('ログイン試行が多すぎます');
  }
});

ユーザー体験を重視する場合

推奨:express-slow-down + express-rate-limit 併用

いきなりブロックせず、段階的に制限:

const limiter = rateLimit({ windowMs: 900000, max: 100 });
const speedLimiter = slowDown({ windowMs: 900000, delayAfter: 50, delayMs: 200 });

app.use('/api/', speedLimiter);
app.use('/api/', limiter);

🚫 非推奨パッケージの扱い

express-bruteexpress-limiter は、新しいプロジェクトでの使用を避けるべきです:

  • 最終更新から長期間経過
  • セキュリティ修正がされていない可能性
  • 現代的な Node.js バージョンとの互換性問題
  • コミュニティサポートが限定的

既存システムで使用している場合は、移行計画を立てることを推奨します:

// 移行例:express-brute → express-rate-limit
// 旧コード
app.post('/login', bruteforce.prevent, loginHandler);

// 新コード
const loginLimiter = rateLimit({
  windowMs: 5 * 60 * 1000,
  max: 5,
  message: 'ログイン試行が多すぎます'
});

app.post('/login', loginLimiter, loginHandler);

📊 機能比較サマリー

機能express-bruteexpress-limiterexpress-rate-limitexpress-slow-downrate-limiter-flexible
メンテナンス❌ 停滞❌ 停滞✅ アクティブ✅ アクティブ✅ アクティブ
Redis 対応
メモリストア
カスタムキー⚠️ 限定的⚠️ 限定的
ポイントシステム
遅延機能⚠️ 要実装
TypeScript
新規推奨

💡 最終的な推奨事項

新規プロジェクトでの選択フロー:

  1. シンプルな API 保護が必要express-rate-limit
  2. Redis 環境が既に整っているexpress-rate-limit または rate-limiter-flexible
  3. 複雑な制限ロジックが必要rate-limiter-flexible
  4. ユーザー体験を重視express-slow-down + express-rate-limit
  5. レガシーシステム維持 → 移行計画を立てて express-rate-limit

重要な注意点:

  • express-bruteexpress-limiter は新規プロジェクトで使用しないでください
  • 本番環境では必ず Redis などの永続ストアを使用してください
  • メモリストアは単一サーバー環境でのみ使用可能です
  • レート制限はセキュリティ層の一つであり、他の対策と併用してください

レート制限パッケージの選択は、アプリケーションの規模、インフラ構成、セキュリティ要件によって異なります。express-rate-limit が最もバランスの取れた選択肢ですが、大規模システムでは rate-limiter-flexible の柔軟性が活きます。ユーザー体験を重視する場合は express-slow-down の併用を検討してください。

選び方: express-rate-limit vs rate-limiter-flexible vs express-slow-down vs express-limiter vs express-brute

  • express-rate-limit:

    express-rate-limit は最も成熟しており、コミュニティサポートが厚いパッケージです。シンプルな設定で始められ、メモリストアから Redis まで対応しています。新規プロジェクトで迷った場合の第一選択肢として推奨され、ドキュメントも充実しています。

  • rate-limiter-flexible:

    rate-limiter-flexible は最も柔軟で、Redis、Memcached、MongoDB など複数のストアをサポートします。マイクロサービス環境や複雑な制限ロジックが必要な場合に適しています。学習コストはやや高いですが、大規模システムでの拡張性が高いです。

  • express-slow-down:

    express-slow-down はリクエストを完全にブロックせず、応答を遅延させるアプローチを取ります。ユーザー体験を損なわずに悪意のあるトラフィックを抑制したい場合に適しています。express-rate-limit と併用して、段階的な制限を実現できます。

  • express-limiter:

    express-limiter は Redis をストレージバックエンドとして使用する場合に適しています。Redis 環境が既に整っており、シンプルな設定で済ませたいプロジェクトに向いています。ただし、複数のストレージオプションを必要とする場合は rate-limiter-flexible の方が柔軟です。

  • express-brute:

    express-brute は古いパッケージで、現在はメンテナンスが停滞しています。ブルートフォース攻撃対策に特化していますが、新しいプロジェクトでの使用は推奨されません。既存のレガシーシステムで既に導入されている場合のみ検討し、新規プロジェクトでは express-rate-limitrate-limiter-flexible の評価を推奨します。

express-rate-limit のREADME

express-rate-limit

tests npm version npm downloads license

Basic rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset. Plays nice with express-slow-down and ratelimit-header-parser.

Usage

The full documentation is available on-line.

import { rateLimit } from 'express-rate-limit'

const limiter = rateLimit({
	windowMs: 15 * 60 * 1000, // 15 minutes
	limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
	standardHeaders: 'draft-8', // draft-6: `RateLimit-*` headers; draft-7 & draft-8: combined `RateLimit` header
	legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
	ipv6Subnet: 56, // Set to 60 or 64 to be less aggressive, or 52 or 48 to be more aggressive
	// store: ... , // Redis, Memcached, etc. See below.
})

// Apply the rate limiting middleware to all requests.
app.use(limiter)

Data Stores

The rate limiter comes with a built-in memory store, and supports a variety of external data stores.

Configuration

All function options may be async. Click the name for additional info and default values.

OptionTypeRemarks
windowMsnumberHow long to remember requests for, in milliseconds.
limitnumber | functionHow many requests to allow.
messagestring | json | functionResponse to return after limit is reached.
statusCodenumberHTTP status code after limit is reached (default is 429).
handlerfunctionFunction to run after limit is reached (overrides message and statusCode settings, if set).
legacyHeadersbooleanEnable the X-Rate-Limit header.
standardHeaders'draft-6' | 'draft-7' | 'draft-8'Enable the Ratelimit header.
identifierstring | functionName associated with the quota policy enforced by this rate limiter.
storeStoreUse a custom store to share hit counts across multiple nodes.
passOnStoreErrorbooleanAllow (true) or block (false, default) traffic if the store becomes unavailable.
keyGeneratorfunctionIdentify users (defaults to IP address).
ipv6Subnetnumber (32-64) | function | falseHow many bits of IPv6 addresses to use in default keyGenerator
requestPropertyNamestringAdd rate limit info to the req object.
skipfunctionReturn true to bypass the limiter for the given request.
skipSuccessfulRequestsbooleanUncount 1xx/2xx/3xx responses.
skipFailedRequestsbooleanUncount 4xx/5xx responses.
requestWasSuccessfulfunctionUsed by skipSuccessfulRequests and skipFailedRequests.
validateboolean | objectEnable or disable built-in validation checks.

Thank You

Sponsored by Zuplo a fully-managed API Gateway for developers. Add dynamic rate-limiting, authentication and more to any API in minutes. Learn more at zuplo.com

zuplo-logo


Thanks to Mintlify for hosting the documentation at express-rate-limit.mintlify.app

Create your docs today


Finally, thank you to everyone who's contributed to this project in any way! 🫶

Issues and Contributing

If you encounter a bug or want to see something added/changed, please go ahead and open an issue! If you need help with something, feel free to start a discussion!

If you wish to contribute to the library, thanks! First, please read the contributing guide. Then you can pick up any issue and fix/implement it!

License

MIT © Nathan Friedly, Vedant K