4 mins read


Rate Limiting


What is Rate Limiting

Rate limiting is a technique that limits the number of requests that can be made to a network, server, or other resource within a specific time frame. It's a key component of security strategies and system management and can help prevent a range of malicious activities, including:-

  1. Brute force attacks
  2. Password brute force
  3. User account takeover
  4. DDoS
  5. Credential stuffing
  6. Inventory hoarding attacks
  7. Data scraping

For example, an API provider might set a rate limit of 60 requests per minute for a specific endpoint. Once a client or application reaches this limit, any further requests are blocked or delayed until the next time window begins.

Types of Rate Limits

  1. User Rate Limits: These restrict the number of requests an individual user can make to a service within a specified timeframe, typically based on user identification methods such as API keys or user accounts. This helps prevent abuse and ensures fair usage among users.

  2. Geographic Rate Limits: These control the rate of requests originating from specific geographic regions, such as countries or IP address blocks. This type of rate limiting can be used to manage traffic load and mitigate region-specific issues, such as localized attacks or compliance with regional regulations.

  3. Server Rate Limits: These limit the number of requests that can be processed by a server within a given period to prevent overload and ensure stable performance. By capping the request rate, server rate limits help maintain server health and prevent service disruptions caused by excessive load.

Implementation

Below is a Fixed Window rate limiting algorithm implemented to limit the number of requests a user can make to the server.

 
import { Redis } from "ioredis";
 
/**
 * Rate Limiter middleware using Redis
 * @param {string} key - Unique key for rate limiting
 * @throws {Error} "Too Many Requests" - if the maximum number of requests
 * within the defined window is reached
 * @throws {Error} "Internal Server Error" - if there is an error accessing Redis
 */
const rateLimiter = async (key: string) => {
  // A namespaced key for storing rate limit information in Redis. The key is prefixed with ratelimit: followed by the provided key
  const redisKey = `ratelimit:${key}`;
  
  // The rate limiting window duration in seconds. Here, it's set to 1 minute (60 seconds)
  const expiration = 1 * 60;
  
  // The maximum number of allowed requests within the time window
  const maxRequests = 5;
  
  // The start time of the rate-limiting window, calculated as the current time in seconds minus the expiration time
  const windowStart = Math.floor(Date.now() / 1000) - expiration;
 
  try {
    // Count the number of requests in the window
    const count = await redis.zcount(redisKey, windowStart, "+inf");
    
    // Throw an error if the maximum number of requests is reached
    if (count >= maxRequests) {
      throw new Error("Too Many Requests");
    }
 
    // Add the current request to the sorted set
    await redis.zadd(redisKey, Date.now(), Date.now());
    
    // Set the expiration of the sorted set
    await redis.expire(redisKey, expiration);
  } catch (error) {
    // Throw an error if there is an error accessing Redis
    throw new Error("Internal Server Error");
  }
};