Basic rate-limiting middleware for Express that slows down responses rather than blocking them outright. Use to limit repeated requests to public APIs and/or endpoints such as password reset.
Plays nice with Express Rate Limit
Note: this module does not share state with other processes/servers by default. This module was extracted from Express Rate Limit 2.x and can work with it's stores:
- Memory Store (default, built-in) - stores hits in-memory in the Node.js process. Does not share state with other servers or processes.
- Redis Store
- Memcached Store
Note: when using express-slow-down and express-rate-limit with an external store, you'll need to create two instances of the store and provide different prefixes so that they don't double-count requests.
$ npm install --save express-slow-down
For an API-only server where the rules should be applied to all requests:
const slowDown = require("express-slow-down");
app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
const speedLimiter = slowDown({
windowMs: 15 * 60 * 1000, // 15 minutes
delayAfter: 100, // allow 100 requests per 15 minutes, then...
delayMs: 500 // begin adding 500ms of delay per request above 100:
// request # 101 is delayed by 500ms
// request # 102 is delayed by 1000ms
// request # 103 is delayed by 1500ms
// etc.
});
// apply to all requests
app.use(speedLimiter);
For a "regular" web server (e.g. anything that uses express.static()
), where the rate-limiter should only apply to certain requests:
const slowDown = require("express-slow-down");
app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
const resetPasswordSpeedLimiter = slowDown({
windowMs: 15 * 60 * 1000, // 15 minutes
delayAfter: 5, // allow 5 requests to go at full-speed, then...
delayMs: 100 // 6th request has a 100ms delay, 7th has a 200ms delay, 8th gets 300ms, etc.
});
// only apply to POST requests to /reset-password/
app.post("/reset-password/", resetPasswordSpeedLimiter, function(req, res) {
// handle /reset-password/ request here...
});
A req.slowDown
property is added to all requests with the following fields:
limit
: The options.delayAfter value (defaults to 1)current
: The number of requests in the current windowremaining
: The number of requests remaining before rate-limiting beginsresetTime
: When the window will reset and current will return to 0, and remaining will return to limit (in milliseconds since epoch - compare to Date.now()). Note: this field depends on store support. It will be undefined if the store does not provide the value.delay
: Amount of delay imposed on current request (milliseconds)
-
windowMs: milliseconds - how long to keep records of requests in memory. Defaults to
60000
(1 minute). -
delayAfter: max number of connections during
windowMs
before starting to delay responses. Number or function that returns a number. Defaults to1
. Set to0
to disable delaying. -
delayMs: milliseconds - how long to delay the response, multiplied by (number of recent hits -
delayAfter
). Defaults to1000
(1 second). Set to0
to disable delaying. -
maxDelayMs: milliseconds - maximum value for
delayMs
after many consecutive attempts, that is, after the n-th request, the delay will be alwaysmaxDelayMs
. Important when your application is running behind a load balancer or reverse proxy that has a request timeout. Defaults toInfinity
.// Example // Given: { delayAfter: 1, delayMs: 1000, maxDelayMs: 20000, } // Results will be: // 1st request - no delay // 2nd request - 1000ms delay // 3rd request - 2000ms delay // 4th request - 3000ms delay // ... // 20th request - 19000ms delay // 21st request - 20000ms delay // 22nd request - 20000ms delay // 23rd request - 20000ms delay // 24th request - 20000ms delay <-- will not increase past 20000ms // ...
-
skipFailedRequests: when
true
failed requests (response status >= 400) won't be counted. Defaults tofalse
. -
skipSuccessfulRequests: when
true
successful requests (response status < 400) won't be counted. Defaults tofalse
. -
keyGenerator: Function used to generate keys. By default user IP address (req.ip) is used. Defaults:
function (req /*, res*/) { return req.ip; }
-
skip: Function used to skip requests. Returning true from the function will skip limiting for that request. Defaults:
function (/*req, res*/) { return false; }
-
onLimitReached: Function to listen the first time the limit is reached within windowMs. Defaults:
function (req, res, options) { /* empty */ }
-
store: The storage to use when persisting rate limit attempts. By default, the MemoryStore is used.
- Note: when using express-slow-down and express-rate-limit with an external store, you'll need to create two instances of the store and provide different prefixes so that they don't double-count requests.
-
headers: Add
X-SlowDown-Limit
,X-SlowDown-Remaining
, and if the store supports it,X-SlowDown-Reset
headers to all responses. Modeled after the equivalent headers in express-rate-limit. Default:false
MIT © Nathan Friedly