TL;DR
Too many failed password attempts can be a denial-of-service (DoS) attack. This guide shows you how to limit the number of login tries from each IP address or user account to protect your system.
How to Avoid Password Check DoS Attacks
- Understand the Problem: A brute-force attack tries many passwords quickly. Without limits, this can overwhelm your server and lock out legitimate users.
- Choose a Limiting Method: You have two main options:
- IP Address Based: Limit attempts per IP address. This is simpler but less accurate if multiple users share an IP (e.g., behind a NAT).
- User Account Based: Limit attempts per username/email. More precise, but requires tracking user accounts.
- Implement Rate Limiting in Your Application Code: This is the most common approach.
Most web frameworks have built-in rate limiting features or libraries you can use.
- Python (Flask Example): Using a library like
Flask-Limiter:from flask import Flask, request from flask_limiter import Limiter app = Flask(__name__) limiter = Limiter(app, key=request.remote_addr, default_limit="10/minute") @app.route('/login', methods=['POST']) @limiter.limit("5 per minute per user") # Limit to 5 attempts per minute per user. def login(): # Your login logic here... return "Login successful!" - Node.js (Express Example): Using a library like
express-rate-limit:const express = require('express'); const rateLimit = require('express-rate-limit'); const app = express(); const limiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 5, // Limit each IP to 5 requests per windowMs message: 'Too many login attempts. Please try again later.' }); app.post('/login', limiter, (req, res) => { // Your login logic here... res.send('Login successful!'); });
- Python (Flask Example): Using a library like
- Implement Rate Limiting at the Web Server Level: Use tools like Nginx or Apache.
- Nginx Example (using
limit_req_zoneandlimit_conn_zone):http { ... limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/m; server { location /login { limit_req zone=mylimit burst=10 nodelay; # Your login handling here } } }
- Nginx Example (using
- Store Attempt Data: If you’re implementing user-based rate limiting, store failed attempt timestamps in a database or cache (e.g., Redis).
- Database Example: Create a table to track username and last attempt time.
- Redis Example: Use Redis counters for each username.
- Lock Accounts After Too Many Failed Attempts: Temporarily disable accounts after exceeding the limit. This adds an extra layer of security.
- Implement a lockout mechanism in your application code.
- Consider using exponential backoff (increase the lockout duration with each failed attempt).
- Monitor Logs: Regularly check logs for suspicious activity, such as repeated failed login attempts from the same IP address.
- Use Strong Passwords and Multi-Factor Authentication: Rate limiting is a defense in depth. Encourage strong passwords and enable MFA whenever possible.

