Nginx 并发限制

这种请求针对某些合法接口的 CC(Challenge Collapsar) 攻击对某些接口进行重复合法访问, 能够有效利用 Nginx 来压低访问频率.

这里面基于 Nginx 的两个模块:

  • ngx_http_limit_conn_module: 单一IP的连接限制( 限制连接并发 )
  • ngx_http_limit_req_module: 单一IP的请求限制( 限制请求并发 )

ngx_http_limit_conn_module

用于对单个 IP 地址限制连接数, 只有正常处理HTTP标头的时候才会被计算为一个连接; 这种请求下, 可以识别出单个 IP
是否只请求连接而不进行任何处理卡住访问链接.

这里配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 这里是 HTTP 请求, 所以放置于 HTTP 块配置之中
http {
# 这里需要在内存之中定义内存区放置请求的标识区域, 注意重启会释放这块区域
# 关键点:
# 1. 设置名为 `limitaddr` 的共享内存区域
# 2. 内存区以 `$binary_remote_addr(客户端请求地址)` 为唯一标识
# 3. 记录保存最大空间 `10m`, 可以根据内存情况和请求情况配置
limit_conn_zone $binary_remote_addr zone=limitaddr:10m;

# 也可以直接限制唯一标识
limit_conn_zone $server_name zone=limitserver:10m;

......

# 之后就是在 HTTP 服务区使用
server {
...
# 这里直接采用 `limit_conn` 确认采用使用哪块限制区并且限制访问连接数
# 启用 `limitaddr` 的内存区并且设置每个IP只允许发起 10 的连接数.
# 注意, 最好做好调研确认接口正常单个 IP 访问阈值, 防止正常访问的请求也被限制.
limit_conn limitaddr 10;

# 也可以限制在某个地方进行设置
location /download/ {
# 针对域名请求的内存标识区, 这里则是对某个访问地址限制
# 针对 `域名/download` 地址访问连接限制下载只允许 100 个连接
limit_conn limitserver 100;

# 同时也可以设置当超过并发限制返回的错误码, 默认返回 503
limit_conn_status 503;
}
}
}

这里流程相对简单:

  • 创建唯一标识记录区( 必须 )
  • 使用记录区并且设置连接数( 必须 )
  • 设置并发超过的错误返回码( 非必须 )

ngx_http_limit_req_module

这个模块则是限制单个IP在时间段之内的同时发起请求数, 即指定每秒/每分/每小时候的最大请求数.

配置参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 这里依旧是 HTTP 请求, 也是需要定义内存区记录
http {
......
# 这里创建内存区记录标识
# 关键点:
# 1. 设置名为 `limitreqaddr` 的共享内存区
# 2. 内存区以 `$binary_remote_addr(客户端请求地址)` 为唯一标识
# 3. 记录保存最大空间 `10m`, 可以根据内存情况和请求情况配置
# 4. 设定请求访问为 单个IP请求1次数/每秒( 单位为秒 ), 也就是每秒只允许一次
limit_req_zone $binary_remote_addr zone=limitreqaddr:10m rate=1r/s;
......

# 之后就是在 HTTP 服务区使用
server{
...
# 这里则是采用 `limit_req` 设置加载 `limitreqaddr` 请求限制区
# 以下采用最简单的配置, 直接限制全局访问每个请求/每秒
limit_req zone=limitreqaddr;

# 这里还有个延迟计数的设置
# 以下是默认最开始不限制, 当并发请求超越 100 的请求的时候就直接开始调用请求限制
limit_req zone=limitreqaddr burst=100;
}
}

这样直接就能对单个请求进行并发限制, 但是请求注意某些高并发的 API 接口很可能会被误伤到, 所以要正确识别出来启用的代价.

测试

一般都是采用 ab 工具来进行访问测试, 如果没有安装可以采用命令:

1
2
3
4
# 这里采用 Debain 操作的 Apt 安装
sudo apt install -y apache2-utils
# 查看版本确认安装完成
ab -V

安装完成之后就可以检测是否生效:

1
2
# 设定同时调用 20 个连接, 同时发起每个连接 40 个请求
ab -n 40 -c 20 http://127.0.0.1/

这里就可以调整不同的数值来测试进行访问测试.

总结

通过单个IP进行IP连接/请求限制就可以处理比较简单的 CC 攻击, 但是实际上这仅仅只能处理 “简单” 的请求; 如果最后连这种方法都失效,
可以考虑采购高防服务器来处理这些问题, 或者直接对指定的 IP 进行拉黑访问.