express-rate-limit 2.13.1 → 2.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -86
- package/lib/express-rate-limit.js +5 -2
- package/lib/memory-store.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Express Rate Limit
|
|
2
2
|
|
|
3
3
|
[](http://travis-ci.org/nfriedly/express-rate-limit)
|
|
4
4
|
[](https://npmjs.org/package/express-rate-limit "View this project on NPM")
|
|
@@ -12,18 +12,17 @@ If you need a more robust solution, I recommend using an addon store or trying o
|
|
|
12
12
|
|
|
13
13
|
### Stores
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
- Memory Store _(default, built-in)_ - stores hits in-memory in the Node.js process. Does not share state with other servers or processes.
|
|
16
|
+
- [Redis Store](https://npmjs.com/package/rate-limit-redis)
|
|
17
|
+
- [Memcached Store](https://npmjs.org/package/rate-limit-memcached)
|
|
18
18
|
|
|
19
19
|
### Alternate Rate-limiters
|
|
20
20
|
|
|
21
21
|
This module was designed to only handle the basics and didn't even support external stores initially. These other options all are excellent pieces of software and may be more appropriate for some situations:
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
- [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter)
|
|
24
|
+
- [express-brute](https://www.npmjs.com/package/express-brute)
|
|
25
|
+
- [rate-limiter](https://www.npmjs.com/package/express-limiter)
|
|
27
26
|
|
|
28
27
|
## Install
|
|
29
28
|
|
|
@@ -36,12 +35,12 @@ $ npm install --save express-rate-limit
|
|
|
36
35
|
For an API-only server where the rate-limiter should be applied to all requests:
|
|
37
36
|
|
|
38
37
|
```js
|
|
39
|
-
var RateLimit = require(
|
|
38
|
+
var RateLimit = require("express-rate-limit");
|
|
40
39
|
|
|
41
|
-
app.enable(
|
|
40
|
+
app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
|
|
42
41
|
|
|
43
42
|
var limiter = new RateLimit({
|
|
44
|
-
windowMs: 15*60*1000, // 15 minutes
|
|
43
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
45
44
|
max: 100, // limit each IP to 100 requests per windowMs
|
|
46
45
|
delayMs: 0 // disable delaying - full speed until the max limit is reached
|
|
47
46
|
});
|
|
@@ -53,73 +52,78 @@ app.use(limiter);
|
|
|
53
52
|
For a "regular" web server (e.g. anything that uses `express.static()`), where the rate-limiter should only apply to certain requests:
|
|
54
53
|
|
|
55
54
|
```js
|
|
56
|
-
var RateLimit = require(
|
|
55
|
+
var RateLimit = require("express-rate-limit");
|
|
57
56
|
|
|
58
|
-
app.enable(
|
|
57
|
+
app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
|
|
59
58
|
|
|
60
59
|
var apiLimiter = new RateLimit({
|
|
61
|
-
windowMs: 15*60*1000, // 15 minutes
|
|
60
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
62
61
|
max: 100,
|
|
63
62
|
delayMs: 0 // disabled
|
|
64
63
|
});
|
|
65
64
|
|
|
66
65
|
// only apply to requests that begin with /api/
|
|
67
|
-
app.use(
|
|
68
|
-
|
|
66
|
+
app.use("/api/", apiLimiter);
|
|
69
67
|
```
|
|
70
68
|
|
|
71
69
|
Create multiple instances to apply different rules to different routes:
|
|
72
70
|
|
|
73
71
|
```js
|
|
74
|
-
var RateLimit = require(
|
|
72
|
+
var RateLimit = require("express-rate-limit");
|
|
75
73
|
|
|
76
|
-
app.enable(
|
|
74
|
+
app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
|
|
77
75
|
|
|
78
76
|
var apiLimiter = new RateLimit({
|
|
79
|
-
windowMs: 15*60*1000, // 15 minutes
|
|
77
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
80
78
|
max: 100,
|
|
81
79
|
delayMs: 0 // disabled
|
|
82
80
|
});
|
|
83
|
-
app.use(
|
|
81
|
+
app.use("/api/", apiLimiter);
|
|
84
82
|
|
|
85
83
|
var createAccountLimiter = new RateLimit({
|
|
86
|
-
windowMs: 60*60*1000, // 1 hour window
|
|
84
|
+
windowMs: 60 * 60 * 1000, // 1 hour window
|
|
87
85
|
delayAfter: 1, // begin slowing down responses after the first request
|
|
88
|
-
delayMs: 3*1000, // slow down subsequent responses by 3 seconds per request
|
|
86
|
+
delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request
|
|
89
87
|
max: 5, // start blocking after 5 requests
|
|
90
|
-
message:
|
|
88
|
+
message:
|
|
89
|
+
"Too many accounts created from this IP, please try again after an hour"
|
|
91
90
|
});
|
|
92
|
-
app.post(
|
|
93
|
-
|
|
91
|
+
app.post("/create-account", createAccountLimiter, function(req, res) {
|
|
92
|
+
//...
|
|
94
93
|
});
|
|
95
94
|
```
|
|
96
95
|
|
|
97
|
-
A `req.rateLimit` property is added to all requests with the `limit`, `current`, and `remaining` number of requests for usage in your application code.
|
|
96
|
+
A `req.rateLimit` property is added to all requests with the `limit`, `current`, and `remaining` number of requests for usage in your application code and, if the store provides it, a resetTime Date object.
|
|
98
97
|
|
|
99
98
|
## Configuration
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
- **windowMs**: milliseconds - how long to keep records of requests in memory. Defaults to `60000` (1 minute).
|
|
101
|
+
- **delayAfter**: max number of connections during `windowMs` before starting to delay responses. Defaults to `1`. Set to `0` to disable delaying.
|
|
102
|
+
- **delayMs**: milliseconds - how long to delay the response, multiplied by (number of recent hits - `delayAfter`). Defaults to `1000` (1 second). Set to `0` to disable delaying.
|
|
103
|
+
- **max**: max number of connections during `windowMs` milliseconds before sending a 429 response. Defaults to `5`. Set to `0` to disable.
|
|
104
|
+
- **message**: Error message returned when `max` is exceeded. Defaults to `'Too many requests, please try again later.'`
|
|
105
|
+
- **statusCode**: HTTP status code returned when `max` is exceeded. Defaults to `429`.
|
|
106
|
+
- **headers**: Enable headers for request limit (`X-RateLimit-Limit`) and current usage (`X-RateLimit-Remaining`) on all responses and time to wait before retrying (`Retry-After`) when `max` is exceeded.
|
|
107
|
+
- **skipFailedRequests**: when `true` failed requests (response status >= 400) won't be counted. Defaults to `false`.
|
|
108
|
+
- **skipSuccessfulRequests**: when `true` successful requests (response status < 400) won't be counted. Defaults to `false`.
|
|
109
|
+
- **keyGenerator**: Function used to generate keys. By default user IP address (req.ip) is used. Defaults:
|
|
110
|
+
|
|
111
111
|
```js
|
|
112
112
|
function (req /*, res*/) {
|
|
113
113
|
return req.ip;
|
|
114
114
|
}
|
|
115
115
|
```
|
|
116
|
-
|
|
116
|
+
|
|
117
|
+
- **skip**: Function used to skip requests. Returning true from the function will skip limiting for that request. Defaults:
|
|
118
|
+
|
|
117
119
|
```js
|
|
118
120
|
function (/*req, res*/) {
|
|
119
121
|
return false;
|
|
120
122
|
}
|
|
121
123
|
```
|
|
122
|
-
|
|
124
|
+
|
|
125
|
+
- **handler**: The function to execute once the max limit is exceeded. It receives the request and the response objects. The "next" param is available if you need to pass to the next middleware. Defaults:
|
|
126
|
+
|
|
123
127
|
```js
|
|
124
128
|
function (req, res, /*next*/) {
|
|
125
129
|
if (options.headers) {
|
|
@@ -135,70 +139,78 @@ function (req, res, /*next*/) {
|
|
|
135
139
|
});
|
|
136
140
|
}
|
|
137
141
|
```
|
|
138
|
-
|
|
142
|
+
|
|
143
|
+
- **onLimitReached**: Function to listen each time the limit is reached. You can use it to debug/log. Defaults:
|
|
144
|
+
|
|
139
145
|
```js
|
|
140
146
|
function (req, res, options) {
|
|
141
147
|
/* empty */
|
|
142
148
|
}
|
|
143
149
|
```
|
|
144
|
-
|
|
150
|
+
|
|
151
|
+
- **store**: The storage to use when persisting rate limit attempts. By default, the [MemoryStore](lib/memory-store.js) is used. It must implement the following in order to function:
|
|
152
|
+
|
|
145
153
|
```js
|
|
146
154
|
function SomeStore() {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
155
|
+
/**
|
|
156
|
+
* Increments the value in the underlying store for the given key.
|
|
157
|
+
* @method function
|
|
158
|
+
* @param {string} key - The key to use as the unique identifier passed
|
|
159
|
+
* down from RateLimit.
|
|
160
|
+
* @param {Store~incrCallback} cb - The callback issued when the underlying
|
|
161
|
+
* store is finished.
|
|
162
|
+
*
|
|
163
|
+
* The callback should be triggered with three values:
|
|
164
|
+
* - error (usually null)
|
|
165
|
+
* - hitCount for this IP
|
|
166
|
+
* - resetTime - JS Date object (optional, but necessary for X-RateLimit-Reset header)
|
|
167
|
+
*/
|
|
168
|
+
this.incr = function(key, cb) {
|
|
169
|
+
// ...
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Decrements the value in the underlying store for the given key. Used only when skipFailedRequests is true
|
|
174
|
+
* @method function
|
|
175
|
+
* @param {string} key - The key to use as the unique identifier passed
|
|
176
|
+
* down from RateLimit.
|
|
177
|
+
*/
|
|
178
|
+
this.decrement = function(key) {
|
|
179
|
+
// ...
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* This callback is called by the underlying store when an answer to the
|
|
184
|
+
* increment is available.
|
|
185
|
+
* @callback Store~incrCallback
|
|
186
|
+
* @param {?object} err - The error from the underlying store, or null if no
|
|
187
|
+
* error occurred.
|
|
188
|
+
* @param {number} value - The current value of the counter
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Resets a value with the given key.
|
|
193
|
+
* @method function
|
|
194
|
+
* @param {[type]} key - The key to reset
|
|
195
|
+
*/
|
|
196
|
+
this.resetKey = function(key) {
|
|
197
|
+
// ...
|
|
198
|
+
};
|
|
199
|
+
}
|
|
187
200
|
```
|
|
188
201
|
|
|
189
|
-
|
|
190
|
-
* MemoryStore: _(default)_ Simple in-memory option. Does not share state when app has multiple processes or servers.
|
|
191
|
-
* [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments.
|
|
192
|
-
* [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A [Memcached](https://memcached.org/)-backed store.
|
|
202
|
+
Available data stores are:
|
|
193
203
|
|
|
204
|
+
- MemoryStore: _(default)_ Simple in-memory option. Does not share state when app has multiple processes or servers.
|
|
205
|
+
- [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments.
|
|
206
|
+
- [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A [Memcached](https://memcached.org/)-backed store.
|
|
194
207
|
|
|
195
208
|
The `delayAfter` and `delayMs` options were written for human-facing pages such as login and password reset forms.
|
|
196
209
|
For public APIs, setting these to `0` (disabled) and relying on only `windowMs` and `max` for rate-limiting usually makes the most sense.
|
|
197
210
|
|
|
198
|
-
|
|
199
211
|
## Instance API
|
|
200
212
|
|
|
201
|
-
|
|
213
|
+
- **resetKey(key)**: Resets the rate limiting for a given key. (Allow users to complete a captcha or whatever to reset their rate limit, then call this method.)
|
|
202
214
|
|
|
203
215
|
## v2 changes
|
|
204
216
|
|
|
@@ -78,10 +78,13 @@ function RateLimit(options) {
|
|
|
78
78
|
if (options.headers) {
|
|
79
79
|
res.setHeader("X-RateLimit-Limit", options.max);
|
|
80
80
|
res.setHeader("X-RateLimit-Remaining", req.rateLimit.remaining);
|
|
81
|
-
if (resetTime) {
|
|
81
|
+
if (resetTime instanceof Date) {
|
|
82
82
|
// if we have a resetTime, also provide the current date to help avoid issues with incorrect clocks
|
|
83
83
|
res.setHeader("Date", new Date().toGMTString());
|
|
84
|
-
res.setHeader(
|
|
84
|
+
res.setHeader(
|
|
85
|
+
"X-RateLimit-Reset",
|
|
86
|
+
Math.ceil(resetTime.getTime() / 1000)
|
|
87
|
+
);
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
|
package/lib/memory-store.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-rate-limit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.2",
|
|
4
4
|
"description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",
|
|
5
5
|
"homepage": "https://github.com/nfriedly/express-rate-limit",
|
|
6
6
|
"author": {
|