Back to all articles
Best Practice DevOps Node.js Security Software Development

Protect Your Application: Implementing Rate Limiting for Login Forms with Express.js and Nginx

Introduction

The security of web applications is of utmost importance, especially when handling sensitive data such as usernames and passwords. One of the most effective methods to prevent brute-force attacks and overloads is rate limiting. In this article, you will learn how to implement rate limiting for a typical login form using Express.js and Nginx.

What is Rate Limiting?

Rate limiting is a technique that restricts the number of requests a server can accept within a given time period. This protects your application from abuse and overload by limiting the number of allowed requests per user or IP address. For login forms, this is particularly important to prevent brute-force attacks, where an attacker attempts to gain access by repeatedly guessing passwords.

Implementing Rate Limiting with Express.js

Express.js is a popular web framework for Node.js, which is excellent for implementing rate limiting. We will use the express-rate-limit package to add rate limiting functionality.

Setting Up the Project

First, create a new Node.js project and install the required dependencies:

mkdir rate-limiting-auth
cd rate-limiting-auth
npm init -y
npm install express express-rate-limit

Creating the Express Server with Rate Limiting

Create a basic Express server in server.js and configure rate limiting for the login routes:

const express = require('express')
const rateLimit = require('express-rate-limit')

const app = express()
app.use(express.json())

// Configure rate limiting for login routes
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // Limit each IP to 5 requests per `window` (here, per 15 minutes)
  message: 'Too many login attempts from this IP, please try again later.',
})

app.post('/login', loginLimiter, (req, res) => {
  const { username, password } = req.body

  // Implement login logic here
  res.send('Login request received')
})

app.listen(3000, () => {
  console.log('Server running on port 3000')
})

Implementing Rate Limiting with Nginx

Nginx is a powerful web server that can also be used as a reverse proxy. It has built-in rate limiting capabilities, which complement your Express.js application well.

Nginx Configuration for Rate Limiting

Edit the Nginx configuration file (usually found at /etc/nginx/nginx.conf or /etc/nginx/sites-available/default):

http {
    # Rate limiting configuration
    limit_req_zone $binary_remote_addr zone=login_zone:10m rate=10r/m;

    server {
        listen 80;

        location /login {
            # Apply rate limiting to the login route
            limit_req zone=login_zone burst=5 nodelay;

            proxy_pass http://localhost:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

In this example, we limit login requests to 10 requests per minute and use a zone named login_zone that allows up to 5 concurrent requests. Requests exceeding the limit will be rejected.

Conclusion

Implementing rate limiting is a crucial step in securing your web application against brute-force attacks and overloads. By combining Express.js and Nginx, you can create a robust and scalable solution that protects your login forms. With the methods described above, you can ensure that your application remains not only secure but also performant.