Skip to content

Commit

Permalink
Add express-rate-limit for all routes to address CodeQL alert
Browse files Browse the repository at this point in the history
  • Loading branch information
cotarr committed Jan 11, 2024
1 parent 766f578 commit 4ab72a7
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 5 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,20 @@ express-session and passport middleware. These routes authenticate with Basic Au
credentials to perform access_token functions. These calls do not require cookies, nor
should they return a cookie.

### Added

In response to GitHub CodeQL security scan, a network request IP address rate limit
was added using express-rate-limit middleware. API routes related to access token functions
may be configured with a different limit from browser web requests. The following new
configuration values are applicable in the .env file.

```
LIMITS_TOKEN_RATE_LIMIT_COUNT=1000
LIMITS_TOKEN_RATE_LIMIT_MS=3600000
LIMITS_WEB_RATE_LIMIT_COUNT=1000
LIMITS_WEB_RATE_LIMIT_MS=3600000
```

### Debug tests

- Update ThunderClient collections to incorporate /panel/unauthorized and /noscope routes.
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ PGSSLMODE=disable
LIMITS_PASSWORD_RATE_LIMIT_COUNT=10
LIMITS_PASSWORD_RATE_LIMIT_MS=3600000
LIMITS_PASSWORD_RATE_LIMIT_COUNT=1000
LIMITS_PASSWORD_RATE_LIMIT_MS=3600000
LIMITS_PASSWORD_RATE_LIMIT_COUNT=1000
LIMITS_PASSWORD_RATE_LIMIT_MS=3600000
OAUTH2_CLIENT_SECRET_AES_KEY="A Secret That Should Be Changed"
OAUTH2_DISABLE_TOKEN_GRANT=false
Expand Down
3 changes: 2 additions & 1 deletion debug/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ by setting 1000 requests per hour.

```
LIMITS_PASSWORD_RATE_LIMIT_COUNT=1000
LIMITS_PASSWORD_RATE_LIMIT_MS=3600000
LIMITS_TOKEN_RATE_LIMIT_COUNT=1000
LIMITS_WEB_RATE_LIMIT_COUNT=1000
```

## Environment Variable Overrides
Expand Down
4 changes: 4 additions & 0 deletions docs/env.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@

<tr><td>LIMITS_PASSWORD_RATE_LIMIT_COUNT</td><td>10</td><td>Includes successful</td></tr>
<tr><td>LIMITS_PASSWORD_RATE_LIMIT_MS</td><td>3600000</td><td></td></tr>
<tr><td>LIMITS_TOKEN_RATE_LIMIT_COUNT</td><td>1000</td><td>Includes successful</td></tr>
<tr><td>LIMITS_TOKEN_RATE_LIMIT_MS</td><td>3600000</td><td></td></tr>
<tr><td>LIMITS_WEB_RATE_LIMIT_COUNT</td><td>1000</td><td>Includes successful</td></tr>
<tr><td>LIMITS_WEB_RATE_LIMIT_MS</td><td>3600000</td><td></td></tr>

<tr><td>OAUTH_CLIENT_SECRET_AES_KEY</td><td>A Secret That Should Be Changed</td><td></td></tr>
<tr><td>OAUTH2_DISABLE_TOKEN_GRANT</td><td>false</td><td></td></tr>
Expand Down
38 changes: 35 additions & 3 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,45 @@ app.get('/favicon.ico', function (req, res, next) {
res.status(204).send(null);
});

/**
* Middleware IP rate limiter for token API routes
*/
const tokenRateLimit = rateLimit({
windowMs: config.limits.tokenRateLimitTimeMs,
max: config.limits.tokenRateLimitCount,
statusCode: 429,
message: 'Too many requests',
standardHeaders: false,
legacyHeaders: false
});

//
// Routes that authenticate by Basic Auth for use of access_tokens
// are handled before the session middleware.
//
app.post('/oauth/token', oauth2.token);
app.post('/oauth/introspect', oauth2.introspect);
app.post('/oauth/token/revoke', oauth2.revoke);
app.post('/oauth/token', tokenRateLimit, oauth2.token);
app.post('/oauth/introspect', tokenRateLimit, oauth2.introspect);
app.post('/oauth/token/revoke', tokenRateLimit, oauth2.revoke);

/**
* Middleware IP rate limiter for web server routes
* All routes beyond this point are subject to network
* request rate limit, when exceeded, returns 429
*/
const webRateLimit = rateLimit({
windowMs: config.limits.webRateLimitTimeMs,
max: config.limits.webRateLimitCount,
statusCode: 429,
message: 'Too many requests',
standardHeaders: false,
legacyHeaders: false
});

// ----------------------------------------------------------
// All routes beyond this point are subject to network
// request rate limit, when exceeded, returns 429
// ----------------------------------------------------------
app.use(webRateLimit);

// ----------------------------------------------------------
// Add fixed delay timer to the GET /login route.
Expand Down
6 changes: 5 additions & 1 deletion server/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ exports.database = {
exports.limits = {
// Rate limit per IP address for POST requests to /login (10 per hour per IP address)
passwordRateLimitCount: parseInt(process.env.LIMITS_PASSWORD_RATE_LIMIT_COUNT || '10'),
passwordRateLimitTimeMs: parseInt(process.env.LIMITS_PASSWORD_RATE_LIMIT_MS || '3600000')
passwordRateLimitTimeMs: parseInt(process.env.LIMITS_PASSWORD_RATE_LIMIT_MS || '3600000'),
tokenRateLimitCount: parseInt(process.env.LIMITS_TOKEN_RATE_LIMIT_COUNT || '1000'),
tokenRateLimitTimeMs: parseInt(process.env.LIMITS_TOKEN_RATE_LIMIT_MS || '3600000'),
webRateLimitCount: parseInt(process.env.LIMITS_WEB_RATE_LIMIT_COUNT || '1000'),
webRateLimitTimeMs: parseInt(process.env.LIMITS_WEB_RATE_LIMIT_MS || '3600000')
};

exports.oauth2 = {
Expand Down

0 comments on commit 4ab72a7

Please sign in to comment.