以下各节介绍常见用例的典型速率限制配置。您可以将所提供的示例规则组合使用,并按自身场景进行调整。
速率限制的主要用例如下:
- 实施细粒度访问控制以保护资源。包括基于 user agent、IP 地址、referrer、host、国家/地区和世界区域等条件的访问控制。
- 防护凭据填充和账户接管攻击。
- 限制单个客户端执行的操作数量。包括防止 bot 抓取、访问敏感数据、批量创建新账户,以及电商平台中的程序化购买。
- 保护 REST API 免受资源耗尽(针对性 DDoS 攻击)和一般滥用。
- 保护 GraphQL API,防止服务器过载并限制操作数量。
一个常见用例是限制单个 user agent 发起的请求速率。以下示例规则允许某移动应用在 10 分钟内最多发起 100 次请求。您也可以再创建一条规则,限制桌面浏览器的请求速率。
| 设置 | 值 |
|---|---|
| 匹配条件 | User Agent 等于 MobileApp |
| 表达式 | http.user_agent eq "MobileApp" |
| 计数特征 | IP |
| 速率(请求数 / 周期) | 100 次请求 / 10 分钟 |
| 动作 | 受管质询(Managed Challenge) |
访问者成功通过受管质询(Managed Challenge)后,Cloudflare 会下发 cf_clearance cookie,将其识别为已验证用户。但恶意行为者可能尝试在多个请求或设备上复用或共享同一个有效的 cf_clearance 值,以绕过额外质询。
此速率限制规则通过限制同一 cf_clearance 值在指定周期内可发起的请求数,帮助缓解此类滥用。合法的人工用户通常不受影响;使用单一 clearance 令牌进行的自动化或重放请求,一旦超过阈值将被拦截。
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /checkout |
| 表达式 | http.request.uri.path eq "/checkout" |
| 计数特征 | Cookie(cf_clearance) |
| 速率(请求数 / 周期) | 100 次请求 / 10 分钟 |
| 动作 | 拦截(Block) |
在控制资源访问时的另一个用例是:将 IP 地址或自治系统编号(ASN)从速率限制规则中排除或纳入。
以下示例规则允许同一 IP 地址对 /status 发起 GET 请求时,每分钟最多 10 次,前提是访问者的 IP 地址不在 partner_ips IP 列表中。
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /status 且请求方法等于 GET 且源 IP 地址不在列表 partner_ips 中 |
| 表达式 | http.request.uri.path eq "/status" and http.request.method eq "GET" and not ip.src in $partner_ips |
| 计数特征 | IP |
| 速率(请求数 / 周期) | 10 次请求 / 1 分钟 |
| 动作 | 受管质询(Managed Challenge) |
部分应用会收到来自其他来源的请求(例如广告跳转到第三方页面)。您可能希望限制各个 referrer 页面产生的请求数量,以便管理配额或避免间接 DDoS 攻击。
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /status 且请求方法等于 GET |
| 表达式 | http.request.uri.path eq "/status" and http.request.method eq "GET" |
| 计数特征 | 标头(Referer)1 |
| 速率(请求数 / 周期) | 100 次请求 / 10 分钟 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。
SaaS 应用或使用 Cloudflare SSL for SaaS 的客户,可能在同一 zone 下拥有数千个主机,为每个主机单独创建规则并不现实。为解决这一问题,可以创建以 host 作为计数特征的速率限制规则。
以下示例规则会按每个 host 跟踪对 /login 端点的请求速率:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /login 且请求方法等于 GET |
| 表达式 | http.request.uri.path eq "/login" and http.request.method eq "GET" |
| 计数特征 | IP 和 Host |
| 速率(请求数 / 周期) | 10 次请求 / 10 分钟 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。
速率限制的典型用例之一是保护登录端点免受 凭据填充(credential stuffing) ↗ 等攻击。以下示例包含三条处罚逐步加重的速率限制规则,用于应对发起过多请求的客户端。
规则 #1
| 设置 | 值 |
|---|---|
| 匹配条件 | 主机名等于 example.com 且 URI 路径等于 /login 且请求方法等于 POST |
| 表达式 | http.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST" |
| 计数特征 | IP |
| 在以下情况递增计数器 | URI 路径等于 /login 且方法等于 POST 且响应码属于 (401, 403) |
| 计数表达式 | http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403} |
| 速率(请求数 / 周期) | 4 次请求 / 1 分钟 |
| 动作 | 受管质询(Managed Challenge) |
规则 #2
| 设置 | 值 |
|---|---|
| 匹配条件 | 主机名等于 example.com 且 URI 路径等于 /login 且请求方法等于 POST |
| 表达式 | http.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST" |
| 计数特征 | IP |
| 在以下情况递增计数器 | URI 路径等于 /login 且请求方法等于 POST 且响应状态码属于 (401, 403) |
| 计数表达式 | http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403} |
| 速率(请求数 / 周期) | 10 次请求 / 10 分钟 |
| 动作 | 受管质询(Managed Challenge) |
规则 #3
| 设置 | 值 |
|---|---|
| 匹配条件 | Host 等于 example.com |
| 表达式 | http.host eq "example.com" |
| 计数特征 | IP |
| 在以下情况递增计数器 | URI 路径等于 /login 且请求方法等于 POST 且响应状态码属于 (401, 403) |
| 计数表达式 | http.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403} |
| 速率(请求数 / 周期) | 20 次请求 / 1 小时 |
| 动作 | 拦截(Block)1 天 |
这些示例规则需要 Business 套餐或更高套餐。
规则 #1 允许每分钟最多 4 次请求,超过后触发受管质询(Managed Challenge)。该配置允许合法客户有几次机会回忆密码。若自动化程序连续发起多次请求,该客户端很可能因未通过受管质询而被拦截。另一方面,若真人在达到规则 #1 的速率阈值后完成并通过质询,规则 #2 将提供下一层防护,允许在随后 10 分钟内最多 10 次请求。对超过第二层阈值的客户端,将适用最严格的规则 #3,将该客户端拦截一天。
这三条规则的计数表达式与规则表达式(也称为缓解表达式)相互独立。配置独立的计数表达式后,匹配条件仅在触发动作时使用。在计数表达式中,您可以基于 HTTP 响应状态码和 HTTP 响应标头设置条件,从而将速率限制与后端逻辑相结合。
您也可以配置两个不同的表达式——计数表达式与规则/缓解表达式——分别定义:
- 用于计算速率的请求。
- 实际对其执行动作的请求。
例如,规则 #3 在计算速率时会考虑返回 401 或 403 HTTP 状态码的 /login POST 请求。但当超过速率限制后,Cloudflare 会拦截同一 IP 发往 example.com 主机的所有请求。有关计数表达式的更多信息,请参阅 请求速率计算。
一次性密码(OTP)与验证端点(例如 /api/otp/validate 或 /account/verify)常成为暴力破解攻击目标。这些端点特别敏感,因为攻击者会用大量不同验证码发起请求,试图猜出有效 OTP。
为这些端点配置速率限制时,请遵循以下指南:
- 精确匹配 URI 路径:规则表达式必须匹配接收攻击流量的路径。创建规则前请在分析中核实路径。针对
/validate/otp的规则不会匹配发往/api/otp/validate的请求。 - 使用基于响应的计数:仅统计返回错误响应(例如
401或403)的请求,避免对提交有效验证码的合法用户进行速率限制。 - 合理设置地理范围:若按国家/地区限制,请确认攻击流量来自您在分析中观察到的全部国家/地区,而非仅其中之一。
以下示例规则通过仅统计失败尝试来保护 OTP 验证端点:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /api/otp/validate 且请求方法等于 POST |
| 表达式 | http.request.uri.path eq "/api/otp/validate" and http.request.method eq "POST" |
| 计数特征 | IP |
| 在以下情况递增计数器 | URI 路径等于 /api/otp/validate 且请求方法等于 POST 且响应状态码属于 (401, 403) |
| 计数表达式 | http.request.uri.path eq "/api/otp/validate" and http.request.method eq "POST" and http.response.code in {401 403} |
| 速率(请求数 / 周期) | 5 次请求 / 1 分钟 |
| 动作 | 拦截(Block)10 分钟 |
上述示例规则需要 Business 套餐或更高套餐。
若您的 OTP 端点对有效与无效验证码均返回 200(结果写在响应正文中),请改用基于请求的计数并设置更低的阈值:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /api/otp/validate 且请求方法等于 POST |
| 表达式 | http.request.uri.path eq "/api/otp/validate" and http.request.method eq "POST" |
| 计数特征 | IP |
| 速率(请求数 / 周期) | 10 次请求 / 1 分钟 |
| 动作 | 受管质询(Managed Challenge) |
您可以使用速率限制来限制客户端可执行的操作次数。具体防护规则取决于您的应用。以下示例针对通过查询字符串参数或 JSON 正文进行的内容抓取(content scraping) ↗。
在本示例中,客户端通过不同的查询字符串参数在电商网站上执行操作(例如查询价格、加入购物车)。例如,客户端发送的典型请求可能类似:
GET https://store.com/merchant?action=lookup_price&product_id=215
Cookie: session_id=12345您的安全团队可能希望限制客户端可查询价格的次数,以防止可能已规避 Cloudflare Bot Management 的 bot 抓取商店的完整目录。
规则 #1
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant 且 URI 查询字符串包含 action=lookup_price |
| 表达式 | http.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price" |
| 计数特征 | IP |
| 速率(请求数 / 周期) | 10 次请求 / 2 分钟 |
| 动作 | 受管质询(Managed Challenge) |
规则 #2
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant 且 URI 查询字符串包含 action=lookup_price |
| 表达式 | http.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price" |
| 计数特征 | IP |
| 速率(请求数 / 周期) | 20 次请求 / 5 分钟 |
| 动作 | 拦截(Block) |
这两条速率限制规则会匹配执行所选操作(本例中为查询价格)的请求,并以 IP 作为计数特征。与上文 /login 示例类似,这两条规则有助于在存在持续(但合法)访问者时减少误报。
若要通过查询字符串参数限制对特定 product_id 的查询,可以将该查询参数作为计数特征添加,从而基于所有请求计算速率,而不区分客户端。以下示例规则将每个 product_id 的查询次数限制为 10 秒内 50 次请求。
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant |
| 表达式 | http.request.uri.path eq "/merchant" |
| 计数特征 | Query(product_id) |
| 速率(请求数 / 周期) | 50 次请求 / 10 秒 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。
您可以采用相同的速率限制规则模式,保护处理预订与预约的应用。
考虑一个通过 JSON 格式请求正文处理操作及其参数的应用。例如,lookup_price 操作可能如下所示:
POST https://api.store.com/merchant
Cookie: session_id=12345
Body:
{
"action": "lookup_price",
"product_id": 215
}在此场景下,您可以编写规则,限制来自各个会话的操作次数:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant 且 JSON 字符串 action 等于 lookup_price |
| 表达式 | http.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price" |
| 计数特征 | Cookie(session_id) |
| 速率(请求数 / 周期) | 10 次请求 / 2 分钟 |
| 动作 | 受管质询(Managed Challenge) |
此示例规则需要高级速率限制(Advanced Rate Limiting)与载荷检查(payload inspection)。
您也可以部署类似以下规则,在不区分发起请求的客户端的情况下,限制对每个 product_id 的查询次数:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant 且 JSON 字段 action 等于 lookup_price |
| 表达式 | http.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price" |
| 计数特征 | JSON 字段(product_id) |
| 速率(请求数 / 周期) | 50 次请求 / 10 秒 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)与载荷检查(payload inspection)。
识别 bot 流量的通用方法是对触发源站大量 403 或 404 响应状态码的请求进行速率限制。这通常表示抓取应用的自动化活动。
在此情况下,您可以配置类似如下的规则:
| 设置 | 值 |
|---|---|
| 匹配条件 | 主机名等于 example.com |
| 表达式 | http.host eq "example.com" |
| 计数特征 | IP |
| 在以下情况递增计数器 | 响应状态码属于 (403, 404) |
| 计数表达式 | http.response.code in {403 404} |
| 速率(请求数 / 周期) | 5 次请求 / 3 分钟 |
| 动作 | 受管质询(Managed Challenge) |
此示例规则需要 Business 套餐或更高套餐。
若要控制自动化来源执行操作的速率,可考虑将速率限制规则与 Bot Management 结合使用。借助 Bot Management,您可以将 bot 分数 作为匹配条件的一部分,使规则仅应用于自动化或疑似自动化流量。例如,对疑似自动化流量可使用最高分数(或阈值)30,对自动化流量使用 10。
若应用使用 cookie 跟踪会话,可以用该 cookie 设定速率限制上下文(即将其作为计数特征)。将速率限制特征设为 Cookie 后,规则会将来自不同 IP 地址但属于同一会话的请求归为一组,这在应对 bot 网络发起的分布式攻击时很常见。
规则 #1
| 设置 | 值 |
|---|---|
| 匹配条件 | Bot 分数小于 30 且 URI 查询字符串包含 action=delete |
| 表达式 | cf.bot_management.score lt 30 and http.request.uri.query contains "action=delete" |
| 计数特征 | Cookie(session_id) |
| 速率(请求数 / 周期) | 10 次请求 / 1 分钟 |
| 动作 | 受管质询(Managed Challenge) |
规则 #2
| 设置 | 值 |
|---|---|
| 匹配条件 | Bot 分数小于 10 且 URI 查询字符串包含 action=delete |
| 表达式 | cf.bot_management.score lt 10 and http.request.uri.query contains "action=delete" |
| 计数特征 | Cookie(session_id) |
| 速率(请求数 / 周期) | 20 次请求 / 5 分钟 |
| 动作 | 拦截(Block) |
这些示例规则需要高级速率限制(Advanced Rate Limiting)与 Bot Management。
若应用不使用会话 cookie,您可以使用 JA3 指纹 识别各个客户端。JA3 指纹是唯一标识符,可供 Bot Management 客户使用,使 Cloudflare 能够识别来自同一客户端的请求。所有客户端(无论是否自动化)都有关联的指纹。
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /merchant 且 Bot 分数小于 10 |
| 表达式 | http.request.uri.path eq "/merchant" and cf.bot_management.score lt 10 |
| 计数特征 | JA3 Fingerprint |
| 速率(请求数 / 周期) | 10 次请求 / 1 分钟 |
| 动作 | 受管质询(Managed Challenge) |
此示例规则需要高级速率限制(Advanced Rate Limiting)与 Bot Management。
API 可能对应用后端造成显著压力,因为 API 请求的计算或响应成本可能很高。这些请求还可能需要复杂操作(例如数据处理与大量数据查询),若被滥用,最终可能导致源站服务器瘫痪。
高级速率限制(Advanced Rate Limiting)可以缓解多种容量型攻击,例如 DDoS 攻击、批量赋值(mass assignment)与数据窃取。
一个常见关注点是限制 POST 操作。对于已认证流量,您可以使用 API Discovery 确定各端点合适的请求速率,然后创建类似如下的速率限制规则:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /endpoint1 且请求方法等于 POST |
| 表达式 | http.request.uri.path eq "/endpoint1" and http.request.method eq "POST" |
| 计数特征 | 标头(x-api-key) |
| 速率(请求数 / 周期) | 按 API Discovery 建议,或通过分析历史流量评估。 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。API Discovery 需要额外许可证。
计数特征可以是任意标头、密钥、令牌、cookie、查询参数,甚至 JSON 正文字段,因为部分 API 会在 JSON 正文中包含 session ID 或 user ID。更多信息请参阅以下各节:
- 若唯一标识符位于 URI 路径中,请参阅 保护资源。
- 若唯一标识符位于 JSON 正文中,请参阅 防止内容抓取(通过正文)。
GET 请求也可能对应用造成过大压力,或影响成本高昂的资源(例如带宽)。例如,考虑一个存储大量文件(如图片)的应用,客户端可通过访问特定 URL 下载文件:
GET https://api.store.com/files/<FILE_ID>
Header: x-api-key=9375您可能希望限制下载次数以避免滥用,但因数据存储规模较大,不想为每个文件单独编写规则。此时可以编写类似如下规则:
| 设置 | 值 |
|---|---|
| 匹配条件 | 主机名等于 api.example.com 且请求方法等于 GET |
| 表达式 | http.host eq "api.example.com" and http.request.method eq "GET" |
| 计数特征 | Path |
| 速率(请求数 / 周期) | 按 API Discovery 建议,或通过分析历史流量评估。 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。
该规则为 https://api.store.com/files/* 下的每个文件定义 10 分钟内 10 次下载的限制。通过使用 Path 作为规则特征,您无需在每次上传带有不同 <FILE_ID> 的新文件时编写新规则。使用此规则时,速率会按每次请求计算,而不区分源 IP 或会话标识符。
您也可以将 Path 与 x-api-key 标头(若没有密钥或令牌,也可使用 IP)组合,设定由 x-api-key 标识的特定客户端可对给定文件下载的最大次数:
| 设置 | 值 |
|---|---|
| 匹配条件 | 主机名等于 api.store.com 且请求方法等于 GET |
| 表达式 | http.host eq "api.example.com" and http.request.method eq "GET" |
| 计数特征 | Path 和标头(x-api-key) |
| 速率(请求数 / 周期) | 按 API Discovery 建议,或通过分析历史流量评估。 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)。
为 GraphQL API 防止服务器过载,可能与为 RESTful API 防止过载有所不同。基于 GraphQL 构建的应用面临的最大挑战之一是:单一路径管理所有对服务器的查询,且每个请求通常都是 POST 操作。这使得难以根据 HTTP 方法与 URI 路径为不同 API 用例设置不同速率限制。
不过,与 RESTful API 使用方法与路径不同,请求目的通常嵌入在正文中,其中包含客户端希望获取或变更的数据信息(按 GraphQL 术语 ↗,mutation 指服务端数据修改),以及执行该操作所需的任何附加数据。
为防止服务器过载,可考虑以下方法:
- 限制特定用户可调用同一 GraphQL operation name 的次数。
- 限制任意给定用户在请求中允许的查询复杂度总量。
- 限制单个请求的查询复杂度。
以下示例基于一个接受电影评论的应用。GraphQL 请求可能如下所示:
POST https://moviereviews.example.com/graphql
Cookie: session_id=12345
Body:
{
"data": {
"createReview": {
"stars": 5,
"commentary": "This is a great movie!"
}
}
}要限制操作速率,可以使用以下规则:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径等于 /graphql 且正文包含 createReview |
| 表达式 | http.request.uri.path eq "/graphql" and http.request.body.raw contains "createReview" |
| 计数特征 | Cookie(session_id) |
| 速率(请求数 / 周期) | 5 次请求 / 1 小时 |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)与载荷检查(payload inspection)。
处理 GraphQL 请求所需的复杂度可能差异很大。由于 API 使用单一端点,很难在请求被处理前判断其复杂度。
为保护源站服务器免受资源耗尽,您需要限制单个客户端在一段时间内可处理的复杂度总量,而不是限制请求次数。Cloudflare 速率限制允许您创建随时间跟踪复杂度的规则,并在达到复杂度预算或限制后拦截后续请求。
此类速率限制要求服务器按请求复杂度为每个已处理请求打分。此外,服务器必须将该分数作为 HTTP 标头加入响应。然后,速率限制机制会使用该信息更新该特定客户端的预算。
例如,以下规则定义每小时总复杂度预算为 1,000:
| 设置 | 值 |
|---|---|
| 匹配条件 | URI 路径包含 /graphql |
| 表达式 | http.request.uri.path eq "/graphql" |
| 计数特征 | Cookie(session_id) |
| 每周期得分 | 1,000 |
| 周期 | 1 小时 |
| 响应标头名称 | score |
| 动作 | 拦截(Block) |
此示例规则需要高级速率限制(Advanced Rate Limiting)与载荷检查(payload inspection)。
当源站服务器处理请求时,会在响应中添加值为源站处理该请求工作量的 score HTTP 标头——例如 100。在接下来一小时内,同一客户端还可以在额外 900 的预算内发起请求。一旦超出该预算,后续请求将被拦截,直至超时过期。
API Shield 客户可以使用 GraphQL 恶意查询防护来保护其 GraphQL API。GraphQL 恶意查询防护会扫描您的 GraphQL 流量,查找可能使源站过载并导致拒绝服务的查询。您可以构建规则,限制传入 GraphQL 查询的查询深度与大小,以拦截可疑的过大或过于复杂的查询。
更多关于 GraphQL 恶意查询防护的信息,请参阅 API Shield 文档。
-
该 HTTP 标头名称对 “referrer” 存在拼写错误。 ↩