Skip to content

Commit 31acea6

Browse files
feat: add slow down middleware (github#26207)
* feat: add slow down middleware Co-authored-by: Peter Bengtsson <[email protected]>
1 parent a29a637 commit 31acea6

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

docker-compose.prod.tmpl.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ services:
1717
ENABLED_LANGUAGES: ${ENABLED_LANGUAGES}
1818
DEPLOYMENT_ENV: ${DEPLOYMENT_ENV}
1919
RATE_LIMIT_MAX: ${RATE_LIMIT_MAX}
20+
SLOW_DOWN_MAX: ${SLOW_DOWN_MAX}
2021
HEROKU_PRODUCTION_APP: true
2122
PORT: 4000
2223
DD_AGENT_HOST: datadog-agent

middleware/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import timeout from './timeout.js'
99
import morgan from 'morgan'
1010
import datadog from './connect-datadog.js'
1111
import rateLimit from './rate-limit.js'
12+
import slowDown from './slow-down.js'
1213
import cors from './cors.js'
1314
import helmet from 'helmet'
1415
import csp from './csp.js'
@@ -212,6 +213,7 @@ export default function (app) {
212213
}
213214

214215
// *** Early exits ***
216+
app.use(slowDown)
215217
app.use(rateLimit)
216218
app.use(instrument(handleInvalidPaths, './handle-invalid-paths'))
217219
app.use(asyncMiddleware(instrument(handleNextDataPath, './handle-next-data-path')))

middleware/slow-down.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import slowDown from 'express-slow-down'
2+
import statsd from '../lib/statsd.js'
3+
4+
const MAX = process.env.SLOW_DOWN_MAX ? parseInt(process.env.SLOW_DOWN_MAX, 10) : 10000
5+
if (isNaN(MAX)) {
6+
throw new Error(`process.env.SLOW_DOWN_MAX (${process.env.SLOW_DOWN_MAX}) not a number`)
7+
}
8+
9+
export default slowDown({
10+
windowMs: 1 * 60 * 1000, // 1 minute window
11+
delayAfter: MAX, // allow MAX requests to go at full-speed, then...
12+
delayMs: 100, // MAX+1 request has a 100ms delay, MAX+2 has a 200ms delay, MAX+3 has 300ms, etc.
13+
maxDelayMs: 9 * 1000, // slightly less than our Express timeout handler
14+
15+
// Function to listen the first time the limit is reached within windowMs. Defaults:
16+
onLimitReached: (request) => {
17+
const tags = [`url:${request.url}`, `ip:${request.ip}`]
18+
statsd.increment('middleware.slow_down', 1, tags)
19+
},
20+
})

package-lock.json

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"dotenv": "^10.0.0",
3030
"express": "^4.17.2",
3131
"express-rate-limit": "^6.0.4",
32+
"express-slow-down": "^1.4.0",
3233
"express-timeout-handler": "^2.2.2",
3334
"flat": "^5.0.2",
3435
"github-slugger": "^1.4.0",

0 commit comments

Comments
 (0)