Skip to content

Tutorial: Advanced Rate Limiting with Zones

This tutorial provides practical, step-by-step examples for implementing advanced rate limiting scenarios using Peakhour's Rate Limit Zones.

Duration: 25 minutes Prerequisites: An understanding of how to create and use Rate Limit Zones. See the How to Configure Rate Limit Zones guide. Learning Goals: Learn how to create multi-stage rate limiting policies, key on different request attributes, and combine rule phases for sophisticated protection.

What You'll Build: Three advanced rate limiting policies to protect an API by user, apply stricter limits for failed logins, and challenge clients that trigger WAF rules.

Scenario 1: Per-User API Rate Limiting

In this scenario, we will rate limit an API based on an API key sent in a header, rather than by IP address. This ensures that different users behind the same IP (like in an office) have their own rate limits.

Create the Rate Limit Zone

  1. Navigate to Rules & Scripting > Rate Limiting.
  2. Create a new zone with the following settings:
    • Name: api_per_key
    • Requests: 1000
    • Interval (seconds): 3600 (1 hour)
    • Block Duration (seconds): 60
  3. Click Add Zone.

Create the Firewall Rule

  1. Navigate to Rules Engine > All Rules.
  2. Click Add New Rule and select the Rate Limit Request phase.
  3. Configure the rule:
    • Rule Name: API Rate Limit by Key
    • Filter: starts_with(http.request.uri.path, "/api/")
  4. Configure the Actions:
    • Add a Rate Limit action group.
    • Select the Add to zone action and choose the api_per_key zone.
    • Select the Check zone action and choose the api_per_key zone.
    • For the Zone Key, select Header. In the text box that appears, enter Authorization. This tells Peakhour to track requests based on the value of the Authorization header. Other key types like IP address, cookie, and network fingerprints are also available. See the Rate Limit Zones guide for a full list.
    • For the Action on exceeding the limit, choose block with a status code of 429.
  5. Save and Commit your changes.

Your API is now protected with a rate limit of 1000 requests per hour for each unique Authorization header value.

Scenario 2: Stricter Limits for Failed Logins

This scenario uses two zones and two rule phases to apply a lenient rate limit to all login attempts, but a much stricter limit to clients who have recently failed to log in.

Create the Zones

Create two new zones: 1. Zone 1 (Lenient): - Name: login_attempts - Requests: 20 - Interval (seconds): 300 (5 minutes) - Block Duration (seconds): 300 2. Zone 2 (Strict): - Name: failed_logins - Requests: 5 - Interval (seconds): 3600 (1 hour) - Block Duration (seconds): 3600

Create the Rules

Rule 1: Track all login attempts (Request Phase)

  1. Create a new rule in the Rate Limit Request phase.
  2. Rule Name: Track All Login Attempts
  3. Filter: http.request.uri.path == "/login" and http.request.method == "POST"
  4. Actions:
    • Add to zone: login_attempts
    • Check zone: login_attempts, Action: block
    • Zone Key: IP address
  5. Save the rule.

Rule 2: Track failed logins (Response Phase)

  1. Create a new rule in the Rate Limit Response phase.
  2. Rule Name: Track Failed Logins
  3. Filter: http.response.code == 401 (Assuming your app returns 401 for failed logins).
  4. Actions:
    • Add to zone: failed_logins
    • Zone Key: IP address
  5. Save the rule.

Rule 3: Block clients with failed logins (Request Phase)

  1. Create another new rule in the Rate Limit Request phase.
  2. Rule Name: Block Failed Login Offenders
  3. Filter: http.request.uri.path == "/login" and http.request.method == "POST"
  4. Actions:
    • Check zone: failed_logins, Action: block
    • Zone Key: IP address
  5. Save the rule.
  6. Important: Drag this rule to be above the "Track All Login Attempts" rule. This ensures the stricter check happens first.

  7. Commit your changes.

Now, all login attempts are tracked. If a client gets a 401 response, they are added to the failed_logins zone. On their next login attempt, the stricter failed_logins limit is checked first, quickly blocking brute-force attempts.

Scenario 3: Rate Limiting Based on WAF Events

This scenario uses the rate_limit_request_late phase, which runs after the WAF, to challenge clients who trigger WAF rules.

Create the Zone

  1. Create a new zone:
    • Name: waf_offenders
    • Requests: 10
    • Interval (seconds): 60
    • Block Duration (seconds): 900 (15 minutes)

Create the Rule

  1. Create a new rule in the Rate Limit Request Late phase.
  2. Rule Name: Challenge WAF Offenders
  3. Filter: any(peakhour.waf.matched_rule.tags[*] == "sql-injection") (This targets requests that triggered a WAF rule tagged with "sql-injection").
  4. Actions:
    • Add to zone: waf_offenders
    • Check zone: waf_offenders, Action: challenge
    • Zone Key: IP address
  5. Save and Commit your changes.

Now, if a client triggers a SQL injection WAF rule, they will be added to the waf_offenders zone. If they make more than 10 such attempts in a minute, they will be presented with a JavaScript challenge instead of being able to probe your application further.