Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
rate-limiter-flexible
Advanced tools
Flexible API rate limiter backed by Redis for distributed node.js applications
The rate-limiter-flexible npm package is a powerful and flexible rate limiting library for Node.js. It supports various backends like Redis, MongoDB, and in-memory storage, making it suitable for distributed systems. It helps in controlling the rate of requests to APIs, preventing abuse, and ensuring fair usage.
Basic Rate Limiting
This feature allows you to set up basic rate limiting using in-memory storage. The example limits a user to 5 requests per second.
const { RateLimiterMemory } = require('rate-limiter-flexible');
const rateLimiter = new RateLimiterMemory({
points: 5, // 5 points
duration: 1, // Per second
});
rateLimiter.consume('user-key')
.then(() => {
// Allowed
})
.catch(() => {
// Blocked
});
Rate Limiting with Redis
This feature demonstrates how to use Redis as a backend for rate limiting. The example limits a user to 10 requests per minute.
const { RateLimiterRedis } = require('rate-limiter-flexible');
const Redis = require('ioredis');
const redisClient = new Redis();
const rateLimiter = new RateLimiterRedis({
storeClient: redisClient,
points: 10, // 10 points
duration: 60, // Per minute
});
rateLimiter.consume('user-key')
.then(() => {
// Allowed
})
.catch(() => {
// Blocked
});
Rate Limiting with MongoDB
This feature shows how to use MongoDB as a backend for rate limiting. The example limits a user to 5 requests per minute.
const { RateLimiterMongo } = require('rate-limiter-flexible');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/rate-limiter', { useNewUrlParser: true, useUnifiedTopology: true });
const rateLimiter = new RateLimiterMongo({
storeClient: mongoose.connection,
points: 5, // 5 points
duration: 60, // Per minute
});
rateLimiter.consume('user-key')
.then(() => {
// Allowed
})
.catch(() => {
// Blocked
});
Rate Limiting with Bursts
This feature allows for burst handling by blocking the user for a specified duration if they exceed the rate limit. The example blocks a user for 10 seconds if they exceed 10 requests per second.
const { RateLimiterMemory } = require('rate-limiter-flexible');
const rateLimiter = new RateLimiterMemory({
points: 10, // 10 points
duration: 1, // Per second
blockDuration: 10, // Block for 10 seconds if consumed more than points
});
rateLimiter.consume('user-key')
.then(() => {
// Allowed
})
.catch(() => {
// Blocked
});
express-rate-limit is a basic rate-limiting middleware for Express applications. It is simpler and less flexible compared to rate-limiter-flexible, but it is easier to set up for basic use cases.
rate-limiter is another rate limiting library for Node.js. It is less feature-rich compared to rate-limiter-flexible and does not support as many backends, but it is straightforward to use for simple rate limiting needs.
bottleneck is a powerful rate limiting and job scheduling library for Node.js. It offers more advanced features like priority queues and job scheduling, making it more suitable for complex use cases compared to rate-limiter-flexible.
Flexible rate limiter and DDoS protector with Redis as broker allows to control requests rate in cluster or distributed environment.
It uses fixed window to limit requests.
Advantages:
inMemoryLimiter
set uppenalty
and reward
methods to change limits on some results of an actionBy bombardier -c 1000 -l -d 10s -r 2500 -t 5s http://127.0.0.1:3000/pricing
Statistics Avg Stdev Max
Reqs/sec 2491.79 801.92 9497.25
Latency 8.62ms 11.69ms 177.96ms
Latency Distribution
50% 5.41ms
75% 7.65ms
90% 15.07ms
95% 27.24ms
99% 70.85ms
HTTP codes:
1xx - 0, 2xx - 25025, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Endpoint is simple Express 4.x route launched in node:latest
and redis:alpine
Docker containers by PM2 with 4 workers
Endpoint is limited by RateLimiterRedis
with config:
new RateLimiterRedis(
{
redis: redisClient,
points: 1000,
duration: 1,
},
);
Note: Performance will be much better on real servers, as for this benchmark everything was launched on one machine
npm i rate-limiter-flexible
Redis client must be created with offline queue switched off
const redis = require('redis');
const { RateLimiterRedis, RateLimiterMemory } = require('rate-limiter-flexible');
const redisClient = redis.createClient({ enable_offline_queue: false });
// It is recommended to process Redis errors and setup some reconnection strategy
redisClient.on('error', (err) => {
});
const opts = {
redis: redisClient,
points: 5, // Number of points
duration: 5, // Per second(s)
execEvenly: false,
blockOnPointsConsumed: 10, // If 10 points consumed in current duration
blockDuration: 30, // block for 30 seconds in current process memory
inMemoryLimiter: new RateLimiterMemory( // It will be used only on Redis error as insurance
{
points: 1, // 1 is fair if you have 5 workers and 1 cluster
duration: 5,
execEvenly: false,
})
};
const rateLimiterRedis = new RateLimiterRedis(opts);
rateLimiterRedis.consume(remoteAddress)
.then(() => {
// ... Some app logic here ...
// Depending on results it allows to fine
rateLimiterRedis.penalty(remoteAddress, 3);
// or rise number of points for current duration
rateLimiterRedis.reward(remoteAddress, 2);
})
.catch((rejRes) => {
if (rejRes instanceof Error) {
// Some Redis error
// Never happen if `inMemoryLimiter` set up
// Decide what to do with it in other case
} else {
// Can't consume
// If there is no error, rateLimiterRedis promise rejected with number of ms before next request allowed
const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
res.set('Retry-After', String(secs));
res.status(429).send('Too Many Requests');
}
});
It manages limits in current process memory, so keep it in mind when use it in cluster
const rateLimiter = new RateLimiterMemory( // It will be used only on Redis error as insurance
{
points: 1, // 1 is fair if you have 5 workers and 1 cluster
duration: 5,
execEvenly: false,
});
// Usage is the same as for RateLimiterRedis
// Except: it never rejects Promise with Error
points
Default: 4
Maximum number of points can be consumed over duration
duration
Default: 1
Number of seconds before points are reset
execEvenly
Default: false
Delay action to be executed evenly over duration
First action in duration is executed without delay.
All next allowed actions in current duration are delayed by formula msBeforeDurationEnd / (remainingPoints + 2)
It allows to cut off load peaks.
Note: it isn't recommended to use it for long duration, as it may delay action for too long
blockOnPointsConsumed
Default: 0
Against DDoS attacks. Blocked key isn't checked by requesting Redis.
Blocking works in current process memory.
Redis is quite fast, however, it may be significantly slowed down on dozens of thousands requests.
blockDuration
Default: 0
Block key for blockDuration
seconds,
if blockOnPointsConsumed
or more points are consumed
inMemoryLimiter
Default: undefined
RateLimiterMemory object to store limits in process memory,
when Redis comes up with any error.
Be careful when use it in cluster or in distributed app.
It may result to floating number of allowed actions.
If an action with a same key
is launched on one worker several times in sequence,
limiter will reach out of points soon.
Omit it if you want strictly use Redis and deal with errors from it
Both Promise resolve and reject returns object of RateLimiterRes
class if there is no any error.
Object attributes:
RateLimiterRes = {
msBeforeNext: 250, // Number of milliseconds before next action can be done
remainingPoints: 0 // Number of remaining points in current duration
}
Returns Promise, which:
rejRes
is Error objectrejRes
is RateLimiterRes
objectrejRes
is RateLimiterRes
objectArguments:
key
is usually IP address or some unique client idpoints
number of points consumed. default: 1
Fine key
by points
number of points for one duration.
Note: Depending on time penalty may go to next durations
Returns Promise
Reward key
by points
number of points for one duration.
Note: Depending on time reward may go to next durations
Returns Promise
FAQs
Node.js rate limiter by key and protection from DDoS and Brute-Force attacks in process Memory, Redis, MongoDb, Memcached, MySQL, PostgreSQL, Cluster or PM
We found that rate-limiter-flexible demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.