-
-
Notifications
You must be signed in to change notification settings - Fork 162
ExpressBrute migration
rate-limiter-flexible
package provides options and API compatible middleware ExpressBruteFlexible
, which makes it easy to migrate from non-maintained and vulnerable to race conditions ExpressBrute
package.
ExpressBruteFlexible
implements the same logic, but with atomic increments instead of get/set, which may get you into trouble in some cases. Note, it works slower on high traffic, as atomic increments cost some performance on store level.
const ExpressBruteFlexible = require('rate-limiter-flexible/lib/ExpressBruteFlexible');
const redis = require('redis');
const http = require('http');
const express = require('express');
const redisClient = redis.createClient({
enable_offline_queue: false,
});
const opts = {
freeRetries: 10,
minWait: 1000,
maxWait: 10000,
lifetime: 30,
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:
-
storeClient
should be added in case of using any limiter type except MEMORY and CLUSTER. -
dbName
may be set if necessary. It depends on limiter type. -
tableName
may be set if all limits data should be stored in one table. -
storeType
should be set to 'knex', if it is used.
Other notes:
-
ExpressBruteFlexible
always works withrefreshTimeoutOnRequest=false
option. - it works only with seconds since
rate-limiter-flexible
duration is in seconds. For example, ifminWait=500
it 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,
refreshTimeoutOnRequest: false, // this is set for ExpressBrute, as ExpressBruteFlexible works only with fixed window
};
./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 500 requests per second, test ExpressBruteFlexible
before going to production with it.
Get started
Middlewares and plugins
Migration from other packages
Limiters:
- Redis
- Memory
- DynamoDB
- Prisma
- MongoDB (with sharding support)
- PostgreSQL
- MySQL
- BurstyRateLimiter
- Cluster
- PM2 Cluster
- Memcached
- RateLimiterUnion
- RateLimiterQueue
Wrappers:
- RLWrapperBlackAndWhite Black and White lists
Knowledge base:
- Block Strategy in memory
- Insurance Strategy
- 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