限制请求数

限制请求数动作统计每个关键字在固定时间窗口内的请求总数。请求数超过拒绝阈值后,OpenResty Edge 对该关键字的后续请求执行指定的拒绝动作;进入新的时间窗口后,计数器重新计数。

适用场景

  • 限制登录尝试、验证码发送或密码重置等敏感操作的调用次数。
  • 对 API 配额或周期内允许的请求总数进行控制。
  • 限制短时间内重复提交、批量查询等自动化行为。

如果希望平滑持续流量,并在调节阈值和拒绝阈值之间延迟请求,请使用限制请求速率

工作原理

OpenResty Edge 根据一个或多个关键字对请求分组。每个分组在自己的固定时间窗口内独立计数;计数超过拒绝阈值后,系统执行拒绝动作。新的时间窗口开始时,该分组的计数器重置为零。

配置方法

在目标应用的页面规则中选择 CC 攻击防御动作 > 限制请求数,然后配置关键字、拒绝阈值、时间窗口和拒绝动作。

限制请求数配置

参数说明

  1. 关键字:用于对请求分组并分别计数。默认使用客户端 IP 地址,也可以选择 URI、URI 参数等选项。支持组合多个关键字。选择 URI 参数或 Cookie 时,还需要指定相应的参数或 Cookie 名称。详见关键字
  2. 拒绝阈值:一个时间窗口内允许的请求数上限。请求数超过该值后,系统执行拒绝动作。
  3. 时间窗口:请求计数的固定时间区间,单位为秒。进入新的时间窗口后,计数器重新计数。
  4. 拒绝动作:达到拒绝条件后执行的操作。详见拒绝动作

关键字

限制请求数的关键字选项

可选的关键字包括:

  • 客户端 IP 地址:例如 1.1.1.1
  • URI:例如 /openresty
  • URI 查询参数:例如 /openresty?arg1=val1 中的 arg1
  • 请求 Cookie:例如 Cookie: c1=v1 中的 c1
  • X-Forwarded-For 中的第一个 IP 地址:例如 X-Forwarded-For: 1.1.1.1, 1.1.1.2 中的 1.1.1.1
  • X-Forwarded-For 中的最后一个 IP 地址:例如 X-Forwarded-For: 1.1.1.1, 1.1.1.2 中的 1.1.1.2
  • 指定的 HTTP 请求头:例如 Host
  • 加密 Cookie:根据 OpenResty Edge 生成的加密 Cookie 区分客户端。请求没有携带加密 Cookie 时,系统需要回退到其他关键字,因此加密 Cookie 必须与其他关键字组合使用

使用 X-Forwarded-For 前,应确保该请求头由可信代理维护,不能由客户端任意伪造。

拒绝动作

达到拒绝条件后,系统可以执行以下预设动作。默认动作为 返回错误页

限制请求数的拒绝动作

  • 关闭请求连接:立即终止与客户端的连接,不再响应请求。
  • 返回错误页:返回错误页面,默认状态码为 503。
  • 完成 hCaptcha 验证:要求客户端通过 hCaptcha 挑战。
  • 完成 OpenResty Edge Captcha 验证:使用 OpenResty Edge 的验证码系统验证用户。
  • 重定向验证:将请求重定向到验证页面,验证通过后才能继续访问。
  • JavaScript 挑战:要求客户端浏览器执行 JavaScript 代码,以区分浏览器和简单的自动化程序。
  • 私有访问 Token:请求客户端认证,没有有效 Token 时执行配置的回退动作。 需要配置回退动作、必要的 页面模板 和 清除时间(默认 60 秒)。详见 私有访问 Token。 此动作在 OpenResty Edge 26.9.1-1 中首次引入。
  • 标记为拒绝:仅将请求标记为拒绝,并继续执行后续规则。此动作于 24.9.1-7 中首次引入。
  • 封禁 IP 地址:在操作系统层面丢弃来源 IP 的所有数据包。此动作于 26.3.1-1 中首次引入。

配置示例

以下配置表示:在每个 60 秒的时间窗口内,同一客户端 IP 地址的第 1 个请求不受限制;请求数超过 1 后,系统返回 503 错误。

限制请求数示例

发布配置后,可以使用 curl 模拟客户端访问。第一次访问不会触发限制;由于测试页面不存在,源站返回 404:

$ curl -i -H 'host: test.com' http://node-host/404.html
HTTP/1.1 404 Not Found
Date: Fri, 04 Sep 2020 04:43:20 GMT
Content-Type: text/html
Content-Length: 150
Connection: keep-alive
Server: openresty+

<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>openresty</center>
</body>
</html>

在同一时间窗口内紧接着发送第二个请求,将触发限制并返回 503:

$ curl -i -H 'host: test.com' http://node-host/404.html
HTTP/1.1 503 Service Temporarily Unavailable
Date: Fri, 04 Sep 2020 04:43:21 GMT
Content-Type: text/html
Content-Length: 194
Connection: keep-alive
Server: openresty+

<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>openresty</center>
</body>
</html>

等待当前时间窗口结束后再次请求,确认计数已经重置。

注意事项

  • 固定时间窗口会在窗口边界重新计数。设置阈值时,应考虑业务是否可能在相邻窗口边界出现正常突发。
  • 只按客户端 IP 地址计数时,共享 NAT 或代理后的用户会共用额度。可以结合 URI、Cookie 或其他可信标识细分请求。
  • 对浏览器用户优先考虑验证码等可恢复的拒绝动作;只有在确认来源 IP 恶意时,才使用操作系统层封禁。