IBM Cloud Docs
Rate limiting best practices

Rate limiting best practices

The following sections cover typical rate limiting configurations for common use cases. You can combine the provided example rules and adjust them to your own scenario.

The main use cases for rate limiting are the following:

  • Enforce granular access control to resources which includes the access control based on criteria such as user agent, IP address, referrer, host, country, and world region.
  • Protect against credential stuffing and account takeover attacks.
  • Limit the number of operations performed by individual clients. Includes preventing scraping by bots, accessing sensitive data, bulk creation of new accounts, and programmatic buying in e-commerce platforms.
  • Protect REST APIs from resource exhaustion (targeted DDoS attacks) and resources from abuse in general.
  • Protect GraphQL APIs by preventing server overload and limiting the number of operations.

Enforcing granular access control

You can use rate limiting to control how users and applications access your resources. Rate limiting helps protect your application from abuse by restricting traffic based on attributes such as user agent, IP address, referrer, or host.

Each of the following examples demonstrates how to configure a rate-limiting rule for a specific access control scenario.

Limiting request by user agent

You can restrict the number of requests that are allowed for a specific user agent. The following rule example allows mobile app users to make up to 100 requests every 10 minutes. You might also create a separate rule limiting the rate for desktop browsers.

Example—Limit requests by user agent
Setting Value
Matching criteria User Agent equals MobileApp
Expression http.user_agent eq "MobileApp"
Counting characteristics IP
Rate (Requests/Period) 100 requests / 10 minutes
Action Managed Challenge

Allowing specific IP addresses or ASNs

Control access by including or excluding certain IP addresses or Autonomous System Numbers (ASNs) from a rate limiting rule.

The following rate limiting rule example allows up to 10 requests per minute from the same IP address and make a GET request to the /status path, provided the IP address is not included in the IP list entitled partner_ips.

Example—Allow specific IPs or ASNs
Setting Value
Matching criteria URI Path equals /status and Request Method equals GET and IP Source Address is not in list partner_ips
Expression http.request.uri.path eq "/status" and http.request.method eq "GET" and not ip.src in $partner_ips
Counting characteristics IP
Rate (Requests/Period) 10 requests / 1 minute
Action Managed Challenge

Limiting requests by referrer

You can limit requests that originate from referrer pages, such as third-party advertisements or external websites. This use case helps to reduce the risk of indirect denial-of-service (DDoS) attacks and helps you to manage request quotas.

Example—Limit requests by referrer
Setting Value
Matching criteria URI Path equals /status and Request Method equals GET
Expression http.request.uri.path eq "/status" and http.request.method eq "GET"
Counting characteristics Header (Referrer). The HTTP header name uses a misspelling of referrer.
Rate (Requests/Period) 100 requests / 10 minutes
Action Block

This example rule requires Advanced Rate Limiting.

Protecting against credential stuffing

You can use rate limiting to protect login endpoints from credential stuffing attacks. Credential stuffing occurs when attackers use automated scripts to try multiple username and password combinations on a login form. Rate limiting helps mitigate these attacks by restricting repeated failed login attempts from the same IP address.

The following examples show three rate-limiting rules that increase restrictions and penalties based on the number of failed login attempts.

Rule 1: Initial protection threshold

Rule 1 allows up to four failed login attempts per minute. When the limit is exceeded, the system triggers a Managed Challenge. This configuration helps legitimate users recover from occasional login errors while discouraging automated bots.

Rule 1 configuration
Setting Value
Matching criteria Hostname equals example.com and URI Path equals /login and Request Method equals POST
Expression http.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST"
Counting characteristics IP
Increment counter when URI Path equals /login and Method equals POST and Response code is in (401, 403)
Counting expression http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests/Period) 4 requests / 1 minute
Action Managed Challenge

Rule 2: Intermediate protection threshold

If legitimate users pass the challenge when reaching rule 1's rate limit, Rule 2 applies additional protection for clients that continue to make failed login attempts. It allows up to 10 failed attempts over 10 minutes before triggering another Managed Challenge.

Rule 2 configuration
Setting Value
Matching criteria Hostname equals example.com and URI Path equals /login and Request Method equals POST
Expression http.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST"
Counting characteristics IP
Increment counter when URI Path equals /login and Request Method equals POST and Response Status Code is in (401, 403)
Counting expression http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests/Period) 10 requests / 10 minutes
Action Managed Challenge

Rule 3: Strict protection threshold

Rule 3 enforces a stronger penalty to clients exceeding the rule 2 threshold by blocking an IP address for one day after 20 failed login attempts within an hour. This rule provides a final defense against persistent attack attempts.

Rule 3 configuration
Setting Value
Matching criteria Host equals example.com
Expression http.host eq "example.com"
Counting characteristics IP
Increment counter when URI Path equals /login and Request Method equals POST and Response Status Code is in (401, 403)
Counting expression http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests/Period) 20 requests / 1 hour
Action Block for 1 day

All these example rules require a business plan or above.

These three rules have a counting expression separate from the rule expression (also known as mitigation expression). When you configure a separate counting expression, the matching criteria is used when an action is triggered. In the counting expression, you can include conditions based on the HTTP response status code and HTTP response headers to integrate the rate limiting with your backend logic.

You can also decide to have two different expressions: a counting expression and a rule/mitigation expression — to define:

  1. The requests used to compute the rate.
  2. The requests actually acted upon.

For example, Rule 3 example computes the rate considering POST requests to /login that returned a 401 or 403 HTTP status code. However, when the rate limit is exceeded, CIS blocks every request to the example.com host generated by the same IP.

Limiting the number of operations

You can use rate limiting to control how many operations a client performs within a specific time period. The rules that you configure depend on your application’s behavior and risk profile.

The following examples show how to prevent content scraping and automated activity that can overload your system or misuse your data. Examples include limiting requests by query string, JSON body parameters, or bot characteristics.

Preventing content scraping by using query string

In this example, clients perform operations (such as price lookups or adding items to a basket) on an e-commerce website through query string parameters. For example, a typical request that is sent by a client might be similar to the following:

GET https://store.com/merchant?action=lookup_price&product_id=215
Cookie: session_id=12345

Your security team might want to consider setting up a limit on the number of times a client can lookup prices to prevent bots — which might have eluded CIS Bot Management — from scraping the store's entire catalog.

Rule 1 configuration
Setting Value
Matching criteria URI Path equals /merchant and URI Query String contains action=lookup_price
Expression http.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price"
Counting characteristics IP
Rate (Requests/Period) 10 requests / 2 minutes
Action Managed Challenge
Rule 2 configuration
Setting Value
Matching criteria URI Path equals /merchant and URI Query String contains action=lookup_price
Expression http.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price"
Counting characteristics IP
Rate (Requests/Period) 20 requests / 5 minutes
Action Block

These two rate limiting rules match requests performing a selected action (look up price, in this example) and use IP as the counting characteristic. Similarly, to the /login example, the two rules help reduce false positives in case of persistent (but legitimate) visitors.

You can limit the lookup of a specific product_id by using a query string parameter. By adding a query parameter as a counting characteristic, the rate is calculated across all requests, regardless of the client.

The following example limits the number of lookups for each product_id to 50 requests in 10 seconds.

Rule limit via query string
Setting Value
Matching criteria URI Path equals /merchant
Expression http.request.uri.path eq "/merchant"
Counting characteristics Query (product_id)
Rate (Requests/Period) 20 requests / 10 seconds
Action Block

This example rule requires Advanced Rate Limiting.

You might follow the same pattern of rate limiting rules to protect applications handling reservations and bookings.

Preventing content scraping by using request body

Consider an application that handles the operation and its parameters through the request body in JSON format. For example, the lookup_price operation might look like the following:

POST https://api.store.com/merchant
Cookie: session_id=12345

Body:
{
  "action": "lookup_price",
  "product_id": 215
}

In this scenario, you can create a following rule to limit the number of actions from individual sessions:

Rule—Limit lookup actions per session
Setting Value
Matching criteria URI Path equals /merchant and JSON String action equals lookup_price
Expression http.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price"
Counting characteristics Cookie (session_id)
Rate (Requests/Period) 10 requests / 2 minutes
Action Managed Challenge

This example rule requires Advanced Rate Limiting and payload inspection.

You can also limit the number of lookups of each product_id regardless of the client making the requests by deploying a rule like the following:

Rule—Limit lookup requests per product ID
Setting Value
Matching criteria URI Path equals /merchant and JSON field action equals lookup_price
Expression http.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price"
Counting characteristics JSON field (product_id)
Rate (Requests/Period) 50 requests / 10 seconds
Action Block

This example rule requires Advanced Rate Limiting and payload inspection.

If the request body is not JSON format, you can use the http.request.body.raw field and regular expressions (along with the matches operator) to achieve the same goal.

Limiting requests from bots

You can use rate limiting to control automated traffic from bots. A common approach is to monitor requests that return a high number of 403 or 404 response status codes, which often indicate automated scraping activity.

In this situation, you might configure a rule similar to the following:

Rule—Limit requests based on response status codes
Setting Value
Matching criteria Hostname equals example.com
Expression http.host eq "example.com"
Counting characteristics IP
Increment counter when Response Status Code is in (401, 403)
Counting expression http.response.code in {401 403}
Rate (Requests/Period) 5 requests / 3 minutes
Action Managed Challenge

This example rule requires a Business plan or above.

To control the rate of actions performed by automated sources, consider use rate limiting rules together with Bot Management. With Bot Management, you can use the bot score as part of the matching criteria to apply the rule only to automated or likely automated traffic. For example, you can use a maximum score (or threshold) of 30 for likely automated traffic and 10 for automated traffic.

You can enhance protection by combining rate limiting with Bot Management. With Bot Management, you can use the bot score as part of the matching criteria to apply the rule only to automated or likely automated traffic.

For example:

  • A bot score lesser than 30 represents likely automated traffic.
  • A bot score lesser than 10 represents confirmed automated traffic.

Limiting requests per session

If your application uses session cookies, use the cookie as the counting characteristic. This method groups requests from different IPs within the same session—useful for detecting distributed bot attacks.

Rule 1

Limit request for bot score less than 30
Setting Value
Matching criteria Bot Score less than 30 and URI Query String contains action=delete
Expression cis.bot_management.score lt 30 and http.request.uri.query contains "action=delete"
Counting characteristics Cookie (session_id)
Rate (Requests/Period) 10 requests / 1 minute
Action Managed Challenge

Rule 2

Limit request for bot score less than 10
Setting Value
Matching criteria Bot Score less than 10 and URI Query String contains action=delete
Expression cis.bot_management.score lt 10 and http.request.uri.query contains "action=delete"
Counting characteristics Cookie (session_id)
Rate (Requests/Period) 20 requests / 5 minutes
Action Block

These example rules require Advanced Rate Limiting and Bot Management.

Using JA3 fingerprints

If the application does not use a session cookie, you can use JA3 fingerprints to identify individual clients. A JA3 fingerprint is a unique identifier, available to customers with Bot Management, that allows CIS to identify requests coming from the same client. All clients have an associated fingerprint, whether they are automated or not.

Limit request by using JA3 Fingerprint
Setting Value
Matching criteria URI Path equals /merchant and Bot Score less than 10
Expression http.request.uri.path eq "/merchant" and cf.bot_management.score lt 10
Counting characteristics JA3 Fingerprint
Rate (Requests/Period) 10 requests / 1 minute
Action Managed Challenge

This example rule requires Advanced Rate Limiting and Bot Management.

Protecting REST APIs

REST APIs can create high load on backend systems because API requests often require intensive processing or large data lookups. Uncontrolled API access can cause performance degradation or even downtime. Use Advanced Rate Limiting to prevent abuse, mitigate volumetric attacks, and protect critical resources.

Protecting resources

Even GET requests can strain the application or consume bandwidth when used for large data downloads, such as files or images.

For instance, consider the following endpoint:

GET https://api.store.com/files/<FILE_ID>
Header: x-api-key=9375

To prevent abuse while allowing legitimate downloads, you can define a rule that limits file requests without writing separate rules for each file.

Rule — Limit file downloads by path
Setting Value
Matching criteria Hostname equals api.example.com and Request Method equals GET
Expression http.host eq "api.example.com" and http.request.method eq "GET"
Counting characteristics Path
Rate (Requests/Period) As suggested by API Discovery or assessed by analyzing past traffic.
Action Block

This example rule requires Advanced Rate Limiting.

This rule limits downloads to 10 requests per 10 minutes per file under https://api.store.com/files/*. By using Path as the counting characteristic, you can avoid creating new rules for every new <FILE_ID>. The rate is calculated per file, regardless of client IP or session ID.

You can further strengthen protection by combining Path with a client identifier such as x-api-key or IP. This approach allows you to restrict the number of downloads a specific client can make for a given file.

Rule — Limit file downloads by path and header
Setting Value
Matching criteria Hostname equals api.store.com and Request Method equals GET
Expression http.host eq "api.example.com" and http.request.method eq "GET"
Counting characteristics Path and Header (x-api-key)
Rate (Requests/Period) As suggested by API Discovery or assessed by analyzing past traffic.
Action Block

This example rule requires Advanced Rate Limiting.

Protecting GraphQL APIs

Preventing server overload for GraphQL APIs can be different from preventing overload for RESTful APIs. One of the biggest challenges that are posed by applications that are built on GraphQL is that a single path manages all queries to the server, and every request is usually a POST operation. This prevents creating different rate limits for different API based on the HTTP method and URI path.

However, instead of using the method and path like a RESTful API, the purpose of the request is usually embedded in the body, which has information on what data the client wants to fetch or mutate (according to GraphQL's terminology for server-side data modification), along with any additional data that is required to carry out the action.

To prevent server overload, consider the following approaches:

  • Limit the number of times a particular user can call the same GraphQL operation name.
  • Limit the total amount of query complexity any given user is allowed to request.
  • Limit any individual request's query complexity.

The following examples are based on an application that accepts reviews for movies.

POST https://moviereviews.example.com/graphql
Cookie: session_id=12345

Body:
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"
    }
  }
}

Limiting the number of operations

To limit the rate of actions, create the following rule:

Limit the number of operations
Setting Value
Matching criteria URI Path equals /graphql and Body contains createReview
Expression http.request.uri.path eq "/graphql" and http.request.body.raw contains "createReview"
Counting characteristics Cookie (session_id)
Rate (Requests/Period) 5 requests / 1 hour
Action Block

This example rule requires Advanced Rate Limiting and payload inspection.

Limiting the total amount of query complexity

The complexity of handling a GraphQL request can vary significantly. Because the API uses a single endpoint, it can be difficult to determine the complexity of each request before it is processed.

To prevent resource exhaustion on the origin server, limit the total request complexity per client over time, rather than limiting the number of requests. CIS Rate Limiting enables you to create rules that track complexity over time and block requests that exceed a defined complexity budget.

This method requires the origin server to assign a complexity score to each request and include that score in the HTTP response header. The rate-limiting mechanism then uses the score information to update the complexity budget for that specific client.

The following example defines a total complexity budget of 1,000 per hour:

Limit the total amount of query complexity
Setting Value
Matching criteria URI Path contains /graphql
Expression http.request.uri.path eq "/graphql"
Counting characteristics Cookie (session_id)
Score per period 1,000
Period 1 hour
Response header name score
Action Block

This example rule requires Advanced Rate Limiting and payload inspection.

When the origin server processes a request, it adds a score HTTP header to the response with a value which indicates how much work the origin has performed to handle it. For example, 100. In the next hour, the same client can perform requests up to an additional budget of 900. As soon as this budget is exceeded, later requests are blocked until the timeout expires.

Limiting any individual query’s complexity

API Shield customers can use GraphQL malicious query protection to protect their GraphQL APIs. This feature scans incoming GraphQL traffic for queries that might overload the origin server and cause a denial-of-service condition.

You can create rules to limit the depth and size of incoming GraphQL queries. These rules help block suspicious or excessively complex queries before they impact performance.