ExpressJS - Rate Limiting
Implementing Rate Limiting in Express.js
Section titled “Implementing Rate Limiting in Express.js”Rate limiting is a crucial security and performance technique for web applications. It restricts the number of requests a user (or IP address) can make in a given time frame. This helps prevent abuse, such as:
- Denial-of-Service (DoS) Attacks: Overwhelming a server with too many requests, degrading performance for legitimate users.
- Brute-Force Attacks: Repeatedly trying to guess credentials on login or password reset endpoints.
- Web Scraping: Preventing bots from aggressively scraping content from your site.
Using express-rate-limit
Section titled “Using express-rate-limit”The express-rate-limit middleware is the industry standard for implementing rate limiting in Express. It’s highly configurable and easy to use. Key options include:
windowMs: The time frame for which requests are checked, in milliseconds. For example,15 * 60 * 1000sets a 15-minute window.max(orlimit): The maximum number of connections to allow during thewindowMsfrom a single IP. Once the limit is exceeded, subsequent requests will be rejected with a429 Too Many Requestsstatus code.message: The error message to send when the limit is exceeded. Can be a string, JSON object, or function.standardHeaders: A boolean (true) to enable standardizedRateLimit-*response headers.legacyHeaders: A boolean (false) to disable the older, non-standardX-RateLimit-*headers.
Installation
Section titled “Installation”Use npm or your preferred package manager to install the dependency.
npm install express-rate-limitImplementation Example
Section titled “Implementation Example”The following code sets up a global rate limiter that allows 100 requests per IP every 15 minutes. It also shows how to create a stricter limiter specifically for an authentication route.
import express from 'express';import rateLimit from 'express-rate-limit';
const app = express();const PORT = 3000;
// Create a general-purpose rate limiterconst apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes) standardHeaders: 'draft-7', // Use standard `RateLimit` header syntax legacyHeaders: false, // Don't send `X-RateLimit-*` headers message: { error: 'Too many requests, please try again after 15 minutes.' },});
// Create a stricter rate limiter for sensitive endpoints like loginconst loginLimiter = rateLimit({ windowMs: 10 * 60 * 1000, // 10 minutes limit: 5, // Limit each IP to 5 login attempts per `window` message: { error: 'Too many login attempts, please try again after 10 minutes.' }, standardHeaders: 'draft-7', legacyHeaders: false,});
// Apply the general limiter to all requests to `/api`app.use('/api', apiLimiter);
// A regular API routeapp.get('/api/data', (req, res) => { res.send('This is public data.');});
// Apply the stricter limiter only to the login routeapp.post('/api/login', loginLimiter, (req, res) => { // ... login logic here ... res.send('Login attempt recorded.');});
app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`);});Testing the Rate Limiter
Section titled “Testing the Rate Limiter”- Run the server (e.g., with
npm run dev). - Make more than 5
POSTrequests tohttp://localhost:3000/api/loginwithin 10 minutes. On the 6th request, you will receive a429 Too Many Requestsresponse with your custom JSON error message. - The response headers will include
RateLimit-Limit(the max requests),RateLimit-Remaining(requests left), andRateLimit-Reset(a timestamp for when the limit resets).