express-rate-limit vs express-brute vs express-slow-down vs rate-limiter-flexible
Express.js 请求频率限制与暴力破解防护方案对比
express-rate-limitexpress-bruteexpress-slow-downrate-limiter-flexible类似的npm包:

Express.js 请求频率限制与暴力破解防护方案对比

express-rate-limit 是标准的请求频率限制中间件,适用于大多数通用场景。express-slow-down 通常与前者配合使用,用于在达到限制前逐渐延迟响应而非直接阻断。rate-limiter-flexible 提供更细粒度的控制和多种存储后端支持,适合复杂架构。express-brute 是早期的暴力破解防护库,但目前已不再维护,建议在新项目中避免使用。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
express-rate-limit57,986,0853,289153 kB822 天前MIT
express-brute0568-2110 年前BSD
express-slow-down030238.7 kB22 小时前MIT
rate-limiter-flexible03,581230 kB93 个月前ISC

Express.js 请求频率限制与暴力破解防护方案对比

在构建 Node.js 后端服务时,保护 API 免受滥用和暴力破解攻击是架构设计中的关键一环。express-bruteexpress-rate-limitexpress-slow-downrate-limiter-flexible 都是用于解决这一问题的中间件,但它们的设计理念、维护状态和适用场景有很大不同。本文将从技术实现、存储支持和维护状态三个维度进行深度对比。

🛠️ 基本配置与用法

这四个包的核心目标都是控制请求频率,但初始化的方式和配置项有所不同。

express-brute 采用类实例化的方式,通常用于特定路由(如登录接口)的暴力破解防护。

// express-brute
const ExpressBrute = require('express-brute');
const store = new ExpressBrute.MemoryStore();
const bruteforce = new ExpressBrute(store);

app.post('/login', bruteforce.prevent, (req, res) => {
  // 处理登录逻辑
});

express-rate-limit 作为全局或路由中间件使用,配置直观,专注于窗口期内的最大请求数。

// express-rate-limit
const rateLimit = require('express-rate-limit');

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

app.use(limiter);

express-slow-down 配置类似 express-rate-limit,但重点在于设置延迟阈值,而非直接阻断。

// express-slow-down
const slowDown = require('express-slow-down');

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

app.use(speedLimiter);

rate-limiter-flexible 需要实例化限制器对象,并配合中间件包装器使用,配置更为灵活。

// rate-limiter-flexible
const { RateLimiterMemory, RateLimiterExpress } = require('rate-limiter-flexible');

const rateLimiter = new RateLimiterMemory({
  points: 10,
  duration: 1
});

app.use(new RateLimiterExpress(rateLimiter).middleware);

💾 存储后端支持

存储后端决定了限制数据保存在哪里,直接影响系统的扩展性和性能。

express-brute 支持内存和 Redis,但配置方式较为老旧,扩展性有限。

// express-brute
const RedisStore = require('express-brute-redis');
const store = new RedisStore({
  host: 'localhost',
  port: 6379
});

express-rate-limit 默认使用内存,但官方支持多种外部存储插件(如 Redis、MongoDB)。

// express-rate-limit
const RedisStore = require('rate-limit-redis');
const limiter = rateLimit({
  store: new RedisStore({
    sendCommand: (...args) => redisClient.call(...args),
  }),
  windowMs: 15 * 60 * 1000,
  max: 100
});

express-slow-down 通常复用 express-rate-limit 的存储配置,两者常一起工作。

// express-slow-down
const RedisStore = require('rate-limit-redis');
const speedLimiter = slowDown({
  store: new RedisStore({
    sendCommand: (...args) => redisClient.call(...args),
  }),
  windowMs: 15 * 60 * 1000
});

rate-limiter-flexible 原生支持最广泛的存储后端,包括 Redis、Memcached、Postgres、Mongo 等。

// rate-limiter-flexible
const { RateLimiterRedis } = require('rate-limiter-flexible');
const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 10,
  duration: 1
});

🔑 自定义键与粒度控制

如何识别用户(IP、UserID、API Key)决定了防护的精准度。

express-brute 默认基于 IP,自定义键需要通过中间件逻辑手动处理,较为繁琐。

// express-brute
app.post('/login', (req, res, next) => {
  bruteforce.handle(new ExpressBrute.Request(req, res), next, {
    id: req.body.username // 手动指定键
  });
}, (req, res) => {
  // 登录成功
});

express-rate-limit 通过 keyGenerator 配置项轻松自定义键,支持基于用户 ID 等逻辑。

// express-rate-limit
const limiter = rateLimit({
  keyGenerator: (req) => {
    return req.user.id || req.ip;
  }
});

express-slow-down 同样支持 keyGenerator,逻辑与 express-rate-limit 一致。

// express-slow-down
const speedLimiter = slowDown({
  keyGenerator: (req) => {
    return req.user.id || req.ip;
  }
});

rate-limiter-flexible 在中间件配置中直接支持 getKey,且支持多维度组合键,灵活性最高。

// rate-limiter-flexible
app.use(new RateLimiterExpress(rateLimiter, {
  getKey: (req) => {
    return `${req.user.id}_${req.ip}`;
  }
}).middleware);

⚠️ 维护状态与安全性

选择库时,维护状态直接关系到安全性。过时的库可能包含未修复的漏洞。

express-brute 已多年未更新,社区普遍认为其不再适合新项目。存在潜在的安全风险,不建议继续使用。

// express-brute
// ⚠️ 警告:该库已不再维护,npm 页面无近期更新
// 建议迁移至 rate-limiter-flexible

express-rate-limit 维护活跃,定期更新以适应 Express 新版本和安全需求。

// express-rate-limit
// ✅ 状态:活跃维护
// 适合大多数标准场景

express-slow-down 维护活跃,通常与 express-rate-limit 同步更新。

// express-slow-down
// ✅ 状态:活跃维护
// 适合作为补充策略

rate-limiter-flexible 维护活跃,专注于提供企业级的灵活性和安全性。

// rate-limiter-flexible
// ✅ 状态:活跃维护
// 适合复杂和高并发场景

📊 总结对比表

特性express-bruteexpress-rate-limitexpress-slow-downrate-limiter-flexible
维护状态❌ 不再维护✅ 活跃✅ 活跃✅ 活跃
主要用途暴力破解防护通用频率限制响应延迟 throttling复杂频率限制
存储支持有限 (Redis/Mem)多 (通过插件)多 (同 rate-limit)极多 (原生支持)
配置复杂度中高
推荐场景旧项目迁移新项目默认选择用户体验优化分布式/复杂系统

💡 架构建议

express-rate-limit 是大多数项目的默认选择 🧰。它简单、可靠,足以应对 90% 的 API 防护需求。配合 express-slow-down 可以在不阻断用户的情况下缓解流量峰值。

rate-limiter-flexible 是复杂系统的首选 🔧。如果你需要基于数据库用户 ID 进行限制,或者需要在 Redis 集群中共享限制状态,它的灵活性和存储支持是无与伦比的。

express-brute 应被视作技术债务 🗑️。虽然它曾经很流行,但现在的替代品更安全、更灵活。如果在新项目中看到它,请务必替换。

最终建议:对于新项目,优先使用 express-rate-limit。如果业务逻辑复杂或需要分布式支持,选择 rate-limiter-flexible。永远不要在新代码中引入 express-brute

如何选择: express-rate-limit vs express-brute vs express-slow-down vs rate-limiter-flexible

  • express-rate-limit:

    选择 express-rate-limit 如果你需要快速搭建标准的频率限制功能。它配置简单,社区支持好,适合大多数 API 防护场景,尤其是只需要基于 IP 或简单键值进行限制的情况。

  • express-brute:

    不建议在新项目中使用。该库已多年未更新,存在潜在的安全维护风险。如果你的旧项目正在使用它,建议尽快迁移到 rate-limiter-flexibleexpress-rate-limit 以获得持续的安全补丁和支持。

  • express-slow-down:

    选择 express-slow-down 当你希望改善用户体验而不是直接返回 429 错误。它适合配合 express-rate-limit 使用,在用户接近限制阈值时逐渐增加响应延迟,给合法用户缓冲空间。

  • rate-limiter-flexible:

    选择 rate-limiter-flexible 如果你需要复杂的限制逻辑,比如基于用户 ID、API 密钥或多维度组合键。它支持多种存储后端(Redis、MongoDB 等),适合高并发或分布式系统架构。

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.
loggerLoggerCustom logger

Thank You


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

Create your docs today


And 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