GX博客

分享个人 Full-Stack JavaScript 项目开发经验

Nginx的防滥用与访问限制

构建一个网站,我们希望确保每个正常用户可以随时地合法访问它。为此,我们需要采取一些措施限制访问滥用的用户,确保网站程序的可用性。


下面是一个防滥用和访问限制的配置例子。它并没有在 location 级别细分限制规则,所以限制将作用于整个虚拟服务器。

http {

    # 省略......

    include my_access.conf;

    limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;

    limit_conn_zone $server_name zone=conn_per_server:10m;

    limit_req_zone $binary_remote_addr zone=req_per_ip:10m rate=20r/s;

    limit_req_zone $server_name zone=req_per_server:10m rate=2000r/s;

    # limit_conn_log_level error;

    # limit_req_log_level error;

    # 立刻释超时套接字在缓冲区的内存
    reset_timedout_connection on;

    server {

        # 省略......

        limit_conn conn_per_ip 10;

        limit_conn conn_per_server 1000;

        limit_req zone=req_per_ip burst=30 nodelay;

        limit_req zone=req_per_server burst=3000 nodelay;

        # 省略......
    }

    # 省略......
}

上面配置中,限制同一 IP 的最大连接数为10,虚拟服务器的最大连接数为1000;限制同一 IP 20个/秒的请求速率,允许最大突发数为30,不作延迟处理;对于虚拟服务器,限制2000个/秒的请求速率,允许最大突发数为3000,不作延迟处理。

相关指令说明如下:


连接数限制

  • limit_conn_zone

    设置共享内存区域的参数,该区域保留各种键的状态。状态包括当前的连接数。(有效区段:http)

    $binary_remote_addr 变量,IPv4 地址大小为4个字节,IPv6 地址大小为16个字节。存储状态在32位平台总是占32或64字节,在64位平台上占64字节。1m 区域可以保留大约32000个32字节状态或大约16000个64字节状态。

    如果区域存储空间耗尽,服务器将向其它所有请求响应 limit_conn_status 指令设置的错误。

  • limit_conn

    设置共享内存区域和 limit_conn_zone 指令给定的键值的最大允许连接数。当且仅当当前级别没有 limit_conn 指令时,这指令才从上一级别继承。

  • limit_conn_status

    设置当超出连接数限制时,拒绝请求时候响应的状态码。默认值为:503(Service Temporarily Unavailable)。

  • limit_conn_log_level

    设置超出连接数限制时使用的日志记录级别。默认值为:error。可选值为:info | notice | warn | error。


了解更多官方 http 连接数限制模块的最新说明,请点击这里

请求速率限制

  • limit_req_zone

    设置共享内存区域的参数,该区域将保留各种键的状态。状态存储当前的请求数。(有效区段:http)

    如果区域存储空间耗尽,则删除最近最少使用的状态。如果在此之后仍然不足以容纳新记录,则返回错误终止请求。此外,为了防止内存耗尽,Nginx 每次创建一个新状态时,它最多会删除两个在过去60秒内未使用过的状态。

    limit_req_zone key zone=name:size rate=rate [sync];

    参数 rate 的单位可以为次每秒(r/s)或者次每分钟(r/m)等。

    Nginx 实际上以毫秒粒度跟踪请求。

  • limit_req

    基于漏桶算法(Leaky Bucket),设置共享内存区域和请求的最大突发大小。

    如果在同一个 server/location 中包含多个 limit_req 指令,会使用最严格的限制。

    当且仅当当前级别没有 limit_req 指令时,这指令才从上一级别继承。

    limit_req zone=name [burst=number] [nodelay | delay=number];

    设置 nodelay 参数,Nginx 会根据 burst 参数在队列中分配插槽并强制执行配置的速率限制,但不是通过间隔排队的方式转发请求。

    在上面配置例子中,限制每个 IP 的请求速率为20个每秒,即每50毫秒处理一个请求,并分配30个插槽处理过多请求。当同时有35个请求从给定 IP 地址到达,Nginx 会立即转发31个请求并标记队列中的30个插槽。超出的4个请求将被拒绝。然后每50毫秒释放一个插槽用于转发新的请求。

    如果配置中使用 delay 方式(默认值为:0),当同时有35个请求从给定 IP 地址到达,Nginx 会立即转发第一个请求,并把后面的30个放入队列,剩余的4个请求被拒绝。然后每50毫秒转发一个排队的请求。这也意味着队列中的第30个请求要等待1.5秒。

    如果配置中 delay 设置为其它小于 burst 的数值,如8,则前8个请求被立马转发,其后的22个请求被延迟处理,分两个阶段限速。

  • limit_req_status

    设置超出请求速率限制时,拒绝请求时候响应的状态码。默认值为:503(Service Temporarily Unavailable)。

  • limit_req_log_level

    为因速率超过而拒绝处理或延时处理请求的情况设置所需的日志记录级别。延时处理会比拒绝处理低一级别。默认值为:error。可选值为:info | notice | warn | error。


了解更多官方 http 请求速率限制模块的最新说明,请点击这里

访问限制

my_access.conf

allow 127.0.0.1;

deny all;

IP 地址可以使用 IPv4 或 IPv6 地址(包括网段)的形式。Nginx 会按顺序检查规则,直到找到匹配的项。

当拒绝访问时,会给客户端响应 403(Forbidden)。

了解更多官方访问限制模块的最新说明,请点击这里

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_34.html