-
-
Notifications
You must be signed in to change notification settings - Fork 189
ExpressBrute migration

Advantages of migration:
- Keep limiting logic with the same options and API.
- Use atomic increments to count allowed requests. Get/set approach implemented in
ExpressBrutemay get you into trouble. - Remove unnecessary
long-timeoutandunderscoredependencies.
Note: there is another way to protect login endpoints described here. It has much better performance and flexibility as it counts failed attempts only.
-
freeRetriesThe number of retries the user has before they need to start waiting (default: 2) -
minWaitThe initial wait time (in milliseconds) after the user runs out of retries (default: 1000 milliseconds) -
maxWaitThe maximum amount of time (in milliseconds) between requests user needs to wait (default: 15 minutes). The wait for a given request is determined by adding the time the user needed to wait for the previous two requests. -
lifetimeThe length of time (in seconds since the last request) to remember the number of requests that have been made by an IP. By default, it will be set tomaxWait * the number of attempts before you hit maxWaitto discourage simply waiting for the lifetime to expire before resuming an attack. With default values this is about 6 hours. -
failCallbackGets called with (req,resp,next,nextValidRequestDate) when a request is rejected (default: ExpressBruteFlexible.FailForbidden) -
attachResetToRequestSpecify whether or not a simplified reset method should be attached atreq.brute.reset.(default: true) -
refreshTimeoutOnRequestAlwaysfalsefor ExpressBruteFlexible. -
handleStoreErrorGets called whenever an error occurs with the persistent store from which ExpressBruteFlexible cannot recover. It is passed an object containing the propertiesmessage(a description of the message),parent(the error raised by the session store), and [key,ip] or [req,res,next] depending on whether or the error occurs duringresetor in the middleware itself. -
prefixUseful when several middlewares should have different counters for the same key. (default: '')
-
keycan be a string or alternatively it can be afunction(req, res, next)that callsnext, passing a string as the first parameter. -
failCallbackSet custom callback on the final fail after all attempts. -
ignoreIPDisregard IP address when matching requests if set totrue. (default: false) -
prefixUseful when several middlewares should have different counters for the same key. (default: '')
req.brute.reset can be called for current request, if attachResetToRequest is true. Alternatively, reset(ip, key, callback) can be called from ExpressBruteFlexible instance. The first argument ip should be set to NULL, if ignoreIp option is true.
const ExpressBruteFlexible = require('rate-limiter-flexible/lib/ExpressBruteFlexible');
const redis = require('redis');
const http = require('http');
const express = require('express');
const redisClient = await redis.createClient({
enable_offline_queue: false,
})
.connect();
const opts = {
freeRetries: 10,
minWait: 1000, // 1 second
maxWait: 10000, // 10 seconds
lifetime: 30, // 30 seconds
storeClient: redisClient,
};
const bruteforce = new ExpressBruteFlexible(
ExpressBruteFlexible.LIMITER_TYPES.REDIS,
opts
);
const app = express();
app.post('/auth',
bruteforce.prevent, // error 429 if we hit this route too often
function (req, res, next) {
res.send('Success!');
}
);ExpressBruteFlexible constructor requires to set a limiter type one from ExpressBruteFlexible.LIMITER_TYPES.*.
The second argument is options.
Options are the same except:
-
storeClientshould be added in case of using any limiter type except MEMORY and CLUSTER. -
dbNamemay be set if necessary. It depends on limiter type. -
tableNamemay be set if all limits data should be stored in one table. -
storeTypeshould be set to 'knex', if it is used.
Other notes:
-
ExpressBruteFlexiblealways works withrefreshTimeoutOnRequest=falseoption. - it works only with seconds since
rate-limiter-flexibleduration is in seconds. For example, ifminWait=500it is1 second.
Express app is launched in 4 processes with redis:5.0.4-alpine in Docker container.
const opts = {
freeRetries: 20,
minWait: 1000,
maxWait: 10000,
lifetime: 30,
// the next option is for ExpressBrute, as ExpressBruteFlexible works only with fixed window
refreshTimeoutOnRequest: false,
};./bombardier -c 500 -l -d 30s -r 1000 -t 5s shoots two endpoints limited by ExpressBrute and ExpressBruteFlexible 1000 times per second during 30 seconds. Every request is assigned with one of 100 random keys.
Statistics Avg Stdev Max
Reqs/sec 997.49 275.09 3663.47
Latency 5.97ms 6.07ms 84.51ms
Latency Distribution
50% 4.17ms
75% 5.24ms
90% 10.14ms
95% 16.06ms
99% 37.72ms
HTTP codes:
1xx - 0, 2xx - 2884, 3xx - 0, 4xx - 27109, 5xx - 0
Statistics Avg Stdev Max
Reqs/sec 1000.76 440.44 3796.22
Latency 23.94ms 19.53ms 204.91ms
Latency Distribution
50% 16.79ms
75% 28.64ms
90% 49.46ms
95% 66.53ms
99% 105.55ms
HTTP codes:
1xx - 0, 2xx - 2601, 3xx - 0, 4xx - 27395, 5xx - 0
Atomic increments slow down requests processing. If your authorization endpoint processes more than 1000 requests per second, test ExpressBruteFlexible before going to production with it.
Get started
Middlewares and plugins
Migration from other packages
Limiters:
- Cluster
- Drizzle
- DynamoDB
- Etcd
- Memcached
- Memory
- MongoDB (with sharding support)
- MySQL
- PM2 Cluster
- PostgreSQL
- Prisma
- Redis
- SQLite
- Valkey: iovalkey and Valkey Glide
- BurstyRateLimiter
- RateLimiterUnion
- RateLimiterQueue
Wrappers:
- AWS SDK v3 Client Rate Limiter
- RLWrapperBlackAndWhite Black and White lists
- RLWrapperTimeouts Timeouts
Knowledge base:
- Block Strategy in memory
- Insurance Strategy
- Periodic sync to reduce number of requests
- Comparative benchmarks
- Smooth out traffic peaks
-
Usage example
- Minimal protection against password brute-force
- Login endpoint protection
- Websocket connection prevent flooding
- Dynamic block duration
- Different limits for authorized users
- Different limits for different parts of application
- Block Strategy in memory
- Insurance Strategy
- Third-party API, crawler, bot rate limiting