Skip to content

Commit 4dffad1

Browse files
authored
[WAF] Update complexity-based rate limiting (#24028)
1 parent 6f3fd77 commit 4dffad1

File tree

6 files changed

+106
-34
lines changed

6 files changed

+106
-34
lines changed

src/content/docs/waf/rate-limiting-rules/best-practices.mdx

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -392,24 +392,19 @@ This type of rate limiting requires that the server scores every served request
392392

393393
For example, the following rule defines a total complexity budget of 1,000 per hour:
394394

395-
| Setting | Value |
396-
| --------------------------- | ------------------------------------- |
397-
| Matching criteria | URI Path contains `/graphql` |
398-
| Expression | `http.request.uri.path eq "/graphql"` |
399-
| Counting characteristics | Cookie (`session_id`) |
400-
| Score rate (score / period) | 1,000 / 1 hour |
401-
| Score location | Response header (`score`) |
402-
| Action | Block |
395+
| Setting | Value |
396+
| ------------------------ | ------------------------------------- |
397+
| Matching criteria | URI Path contains `/graphql` |
398+
| Expression | `http.request.uri.path eq "/graphql"` |
399+
| Counting characteristics | Cookie (`session_id`) |
400+
| Score per period | 1,000 |
401+
| Period | 1 hour |
402+
| Response header name | `score` |
403+
| Action | Block |
403404

404405
_This example rule requires Advanced Rate Limiting and payload inspection._
405406

406-
:::note
407-
408-
Currently, you can only create complexity-based (or score-based) rules such as the one above [via API](/waf/rate-limiting-rules/create-api/#example-d---complexity-based-rate-limiting-rule).
409-
410-
:::
411-
412-
When the origin server processes a request, it adds a `score` HTTP header to the response with a value representing how much work the origin has performed to handle it — for example, `400`. In the next hour, the same client can perform requests up to an additional budget of `600`. As soon as this budget is exceeded, later requests will be blocked until the timeout expires.
407+
When the origin server processes a request, it adds a `score` HTTP header to the response with a value representing 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 will be blocked until the timeout expires.
413408

414409
### Limit any individual query’s complexity
415410

src/content/docs/waf/rate-limiting-rules/create-api.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,19 @@ The new rule does not consider requests for cached assets when calculating the r
128128
### Example D - Complexity-based rate limiting rule
129129

130130
:::note
131-
[Complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting) is available in beta and can only be configured via API.
131+
[Complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting) is only available to Enterprise customers with Advanced Rate Limiting.
132132
:::
133133

134134
This example adds a rate limiting rule to the `http_ratelimit` phase entry point ruleset for the zone with ID `$ZONE_ID`. The phase entry point ruleset already exists, with ID `$RULESET_ID`.
135135

136-
The new rule is a complexity-based rate limiting rule that takes the `my-score` HTTP response header into account to calculate a total complexity score for the client. The counter with the total score is updated when there is a match for the rate limiting rule's counting expression (in this case, the same as the rule expression since `counting_expression` is an empty string). When this total score becomes larger than `400` during a period of `60` seconds, any later client requests will be blocked for a period of `600` seconds (10 minutes).
136+
The new rule is a complexity-based rate limiting rule that takes the `my-score` HTTP response header into account to calculate a total complexity score for the client. The counter with the total score is updated when there is a match for the rate limiting rule's counting expression (in this case, the same as the rule expression since `counting_expression` is an empty string). When this total score becomes larger than `400` during a period of `60` seconds (one minute), any later client requests will be blocked for a period of `600` seconds (10 minutes).
137137

138138
<APIRequest
139139
path="/zones/{zone_id}/rulesets/{ruleset_id}/rules"
140140
method="POST"
141141
json={{
142142
description: "My complexity-based rate limiting rule",
143-
expression: 'http.request.uri.path matches "^/graphql/"',
143+
expression: '(http.request.uri.path wildcard "/graphql/*")',
144144
action: "block",
145145
ratelimit: {
146146
characteristics: ["cf.colo.id", 'http.request.headers["x-api-key"]'],

src/content/docs/waf/rate-limiting-rules/create-zone-dashboard.mdx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,32 @@ import { Render, Tabs, TabItem } from "~/components";
3232

3333
8. (Optional) To define an expression that specifies the conditions for incrementing the rate counter, enable **Use custom counting expression** and set the expression. By default, the counting expression is the same as the rule expression. The counting expression can include [response fields](/ruleset-engine/rules-language/fields/reference/?field-category=Response).
3434

35-
9. Under **When rate exceeds**, define the maximum number of requests and the time period to consider when determining the rate.
35+
9. (Optional) In **When rate exceeds**, select between:
36+
- **Request based**: Rate limiting based on the number of incoming requests during a given period.
37+
- **Complexity based**: Rate limiting based on the complexity or cost of handling requests during a given period.
3638

37-
10. Under **Then take action**, select the rule action from the **Choose action** drop-down list. For example, selecting _Block_ tells Cloudflare to refuse requests in the conditions you specified when the request limit is reached.
39+
:::note
40+
[Complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting) is only available to Enterprise customers with Advanced Rate Limiting. Other users will always use request-based rate limiting.
41+
:::
3842

39-
11. (Optional) If you selected the _Block_ action, you can [configure a custom response](#configure-a-custom-response-for-blocked-requests) for requests exceeding the configured rate limit.
43+
10. If you selected **Request based** in the previous step (or if you could not select the rate limiting method), enter a value for:
44+
- **Requests**: Maximum number of requests.
45+
- **Period**: Time period to consider when determining the rate.
4046

41-
12. Select the mitigation timeout in the **Duration** dropdown. This is the time period during which Cloudflare applies the select action once the rate is reached.
47+
If you selected **Complexity based**, enter a value for:
48+
- **Score per period**: Maximum score per period. When this value is exceeded, the rule action will execute.
49+
- **Period**: Time period to consider when determining the rate.
50+
- **Response header name**: Name of HTTP header in the response, set by the origin server, with the score for the current request.
51+
52+
11. Under **Then take action**, select the rule action from the **Choose action** drop-down list. For example, selecting _Block_ tells Cloudflare to refuse requests in the conditions you specified when the request limit is reached.
53+
54+
12. (Optional) If you selected the _Block_ action, you can [configure a custom response](#configure-a-custom-response-for-blocked-requests) for requests exceeding the configured rate limit.
55+
56+
13. Select the mitigation timeout in the **Duration** dropdown. This is the time period during which Cloudflare applies the select action once the rate is reached.
4257

4358
Enterprise customers with a paid add-on can [throttle requests](/waf/rate-limiting-rules/parameters/#with-the-following-behavior) instead of applying the configured action for a selected duration. To throttle requests, under **With the following behavior** select _Throttle requests over the maximum configured rate_.
4459

45-
13. To save and deploy your rule, select **Deploy**. If you are not ready to deploy your rule, select **Save as Draft**.
60+
14. To save and deploy your rule, select **Deploy**. If you are not ready to deploy your rule, select **Save as Draft**.
4661

4762
</TabItem> <TabItem label="New dashboard" icon="rocket">
4863

src/content/docs/waf/rate-limiting-rules/parameters.mdx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,21 @@ If you set a custom counting expression, it will not automatically extend the ru
8484
For example, you might want to perform rate limiting for clients sending more than five requests to `/api/` resulting in a `403` HTTP status code from the origin server. In this case, the matching expression would be `starts_with(http.request.uri.path, "/api/")` and the counting expression would be `http.response.code eq 403 and starts_with(http.request.uri.path, "/api/")`. If the counting expression did not include the matching expression (that is, if you had set the counting expression to `http.response.code eq 403`), any response with a `403` status code on any URL would increase the counter.
8585
:::
8686

87+
### When rate exceeds
88+
89+
- Field name in the API: _N/A_ (different API fields required according to the selected option)
90+
91+
The rate limiting counting can be:
92+
93+
- **Request based**: Performs rate limiting based on the number of incoming requests during a given period. This is the only counting method when complexity-based rate limiting is not available.
94+
- **Complexity based**: Performs rate limiting based on the [complexity](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting) or cost of handling requests during a given period. Only available to Enterprise customers with Advanced Rate Limiting.
95+
8796
### When rate exceeds > Requests
8897

8998
- Data type: <Type text="Integer" />
9099
- Field name in the API: `requests_per_period`
91100

92-
The number of requests over the period of time that will trigger the rule.
101+
The number of requests over the period of time that will trigger the rule. Applies to request-based rate limiting.
93102

94103
### When rate exceeds > Period
95104

@@ -100,6 +109,20 @@ The period of time to consider (in seconds) when evaluating the request rate. Th
100109

101110
The available API values are: `10`, `60` (one minute), `120` (two minutes), `300` (five minutes), `600` (10 minutes), or `3600` (one hour).
102111

112+
### When rate exceeds > Score per period
113+
114+
- Data type: <Type text="Integer" />
115+
- Field name in the API: `score_per_period`
116+
117+
Maximum score per period. When this value is exceeded, the rule action will execute. Applies to [complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting).
118+
119+
### When rate exceeds > Response header name
120+
121+
- Data type: <Type text="String" />
122+
- Field name in the API: `score_response_header_name`
123+
124+
Name of HTTP header in the response, set by the origin server, with the score for the current request. Applies to [complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting).
125+
103126
### Then take action
104127

105128
- Data type: <Type text="String" />
@@ -111,9 +134,9 @@ Use one of the following values in the API: `block`, `challenge`, `js_challenge`
111134

112135
If you select the _Block_ action, you can define a custom response using the following parameters:
113136

114-
- [**With response type**](#with-response-type-for-block-action)
115-
- [**With response code**](#with-response-code-for-block-action)
116-
- [**Response body**](#response-body-for-block-action)
137+
- [With response type](#with-response-type-for-block-action)
138+
- [With response code](#with-response-code-for-block-action)
139+
- [Response body](#response-body-for-block-action)
117140

118141
#### With response type (for _Block_ action)
119142

src/content/docs/waf/rate-limiting-rules/request-rate.mdx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,23 @@ Request 4 matches the rule expression and therefore Cloudflare evaluates the rat
116116
## Complexity-based rate limiting
117117

118118
:::note
119-
Complexity-based rate limiting is available in beta to Enterprise customers with Advanced Rate Limiting, and can only be configured via API.
119+
Only available to Enterprise customers with Advanced Rate Limiting.
120120
:::
121121

122122
A complexity-based rate limiting rule performs rate limiting based on the complexity or cost of handling requests during a given period, instead of the number of requests in the same period.
123123

124124
A common use case is to score each request with an estimate of the cost (or complexity) required to serve that request. The rate limiting rule can then enforce a maximum limit on the total complexity that each client can put on the application over a given period, regardless of the total number of requests sent by that client.
125125

126-
When you configure a complexity-based rate limiting rule, the origin server must include an HTTP header in the response with its complexity score.
126+
When you configure a complexity-based rate limiting rule, the origin server must include an HTTP header in the response with its complexity score. This score corresponds to the complexity (or cost) of serving the current request. The score value must be between 1 and 1,000,000.
127127

128128
Complexity-based rate limiting rules must contain the following properties:
129129

130-
- **Score** (API field: `score_per_period`): Maximum score per period. When this value is exceeded, the rule action will execute.
131-
- **Score response header name** (API field: `score_response_header_name`): Name of HTTP header in the response, set by the origin server, with the score for the current request. The score corresponds to the complexity (or cost) of serving the current request. The score value must be between 1 and 1,000,000.
130+
- [Score per period](/waf/rate-limiting-rules/parameters/#when-rate-exceeds--score-per-period): Maximum score per period. When this value is exceeded, the rule action will execute.
131+
- [Period](/waf/rate-limiting-rules/parameters/#when-rate-exceeds--period): The period of time to consider when evaluating the request rate.
132+
- [Response header name](/waf/rate-limiting-rules/parameters/#when-rate-exceeds--response-header-name): Name of HTTP header in the response, set by the origin server, with the score for the current request.
132133

133134
Cloudflare keeps counters with the total score of all requests with the same values for the rule characteristics that match the rule expression. The score increases by the value provided by the origin in the response when there is a match for the counting expression (by default, it is the same as the rule expression). When the total score is larger than the configured maximum score per period, the rule action is applied.
134135

135136
If the origin server does not provide the HTTP response header with a score value or if the score value is outside of the allowed range, the corresponding rate limiting counter will not be updated.
136137

137-
For an example of a complexity-based rate limiting rule, refer to [Create rate limiting rules via API](/waf/rate-limiting-rules/create-api/#example-d---complexity-based-rate-limiting-rule).
138+
For an example of a complexity-based rate limiting rule, refer to [Rule examples](/waf/rate-limiting-rules/use-cases/#example-4).

src/content/docs/waf/rate-limiting-rules/use-cases.mdx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Rule characteristics:
4141

4242
- _Data center ID_ (included by default when creating the rule in the dashboard)
4343
- _IP Address_
44-
- _HTTP Header_ > `x-api-key`
44+
- _Header value of_ > `x-api-key`
4545

4646
</Example>
4747

@@ -58,6 +58,44 @@ Rule characteristics:
5858

5959
- _Data center ID_ (included by default when creating the rule in the dashboard)
6060
- _IP Address_
61-
- _HTTP Header_ > `user-agent`
61+
- _Header value of_ > `user-agent`
6262

6363
</Example>
64+
65+
## Example 4
66+
67+
:::note
68+
[Complexity-based rate limiting](/waf/rate-limiting-rules/request-rate/#complexity-based-rate-limiting) is only available to Enterprise customers with Advanced Rate Limiting.
69+
:::
70+
71+
The following [rate limiting rule](/waf/rate-limiting-rules/create-zone-dashboard/) performs complexity-based rate limiting. The rule takes into account the `my-score` HTTP response header provided by the origin server to calculate a total complexity score for the client with the provided API key.
72+
73+
The counter with the total score is updated when there is a match for the rate limiting rule's [counting expression](/waf/rate-limiting-rules/parameters/#increment-counter-when) (in this case, the same as the rule expression since a counting expression was not provided). When this total score becomes larger than `400` during a period of one minute, any later client requests will be blocked for a period of 10 minutes.
74+
75+
<Example>
76+
77+
Expression:<br />
78+
`(http.request.uri.path wildcard "/graphql/*")`
79+
80+
Rule characteristics:
81+
82+
- _Data center ID_ (included by default when creating the rule in the dashboard)
83+
- _Header value of_ > `x-api-key`
84+
85+
When rate exceeds: **Complexity based**
86+
87+
- Score per period: `400`
88+
- Period: _1 minute_
89+
- Response header name: `my-score`
90+
91+
Then take action:
92+
93+
- Choose action: _Block_
94+
95+
With the following behavior: **Block for the selected duration**
96+
97+
- Duration: _10 minutes_
98+
99+
</Example>
100+
101+
For an API example with this rule configuration, refer to [Create a rate limiting rule via API](/waf/rate-limiting-rules/create-api/#example-d---complexity-based-rate-limiting-rule).

0 commit comments

Comments
 (0)