当前位置:首页 > 运维 > 正文内容

Nginx中对同一IP限速限流DDOS预防

phpmianshi6年前 (2015-04-15)运维812
作用:
Nginx通过limit_conn_zone和limit_req_zone对同一个IP地址进行限速限流,可防止DDOS/CC和flood攻击

limit_conn_zone是限制同一个IP的连接数,而一旦连接建立以后,客户端会通过这连接发送多次请求,那么limit_req_zone就是对请求的频率和速度进行限制。

(注意,tcp连接是有状态的,而构建在tcp之上的http却是无状态的协议)。
通过打开一个网页,然后通过wareshark可以看到,一个连接建立后(即三次握手后),在这个连接断开之前(即四次挥手之前),会有很多的http request,这就是他们的区别:即一个连接的生命周期中,会存在一个或者多个请求,这是为了加快效率,避免每次请求都要三次握手建立连接,现在的HTTP/1.1协议都支持这种特性,叫做keepalive。

首先看看限制连接数,限制每个ip的并发请求
在Nginx的http配置如下:
limit_conn_zone $binary_remote_addr zone=Addr:10m;
然后在Nginx的server段配置如下:
limit_conn Addr 2;
这里两行虽然不是在一起配置,它们之间通过Addr这个变量名联系在一起。你可以对某个目录或指定后缀比如.html或.jpg进行并发连接限制,因为不同资源连接数是不同的。
有了连接数限制,相当于限制了客户端浏览器和Nginx之间 的管道个数,那么浏览器通过这个管道运输请求,如同向自来水管中放水,水的流速和压力对于管道另外一端是有影响的。为了防止不信任的客户端通过这个管道疯狂发送请求,对我们的耗CPU的资源URL不断发出狂轰滥炸,必须对请求的速度进行限制,如同对水流速度限制一样。
限制每个ip的访问频率,在Nginx.conf的http段配置:
limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
在Nginx.conf的server段配置
limit_req zone=one burst=10;
这里引入burst漏桶原理,结合rate速率每秒5个请求(rate=5r/s)解释如下:
  • rate=5r/s:从单一IP地址每秒5个请求是允许的,

  • burst=10:允许超过频率rate限制的请求数不多于10个

  • 当每秒请求超过5个,但是在10个以下,也就是每秒请求的数量在5到10之间的请求将被延时 delay,虽然这里没有明写delay,默认是延时,因为漏洞其实类似队列Queue或消息系统, 当每秒请求数量超过最低速率每秒5个时,多余的请求将会进入这个队列排队等待。如同机场安检,一次放入5个,多于5个,小于10个的排队等待,注意:这个队列或漏洞是以每秒为单位的

  • 如果每秒请求数超过10个,也就是burst的限制,那么也不排队了直接回绝,返回503错误。也就是说排队长度不能超过10个。

  • Zone — 定义了存储每个IP地址状态和它访问受限请求URL的频率的共享内存区域。将这些信息保存在共享内存中,意味着这些信息能够在NGINX工作进程之间共享。定义有两个部分:由zone=关键字标识的区域名称,以及冒号后面的区域大小。约16000个IP地址的状态信息消耗1M内存大小,因此我们的区域(zone)大概可以存储约160000个地址。当NGINX需要添加新的记录时,如果此时存储耗尽了,最老的记录会被移除。如果释放的存储空间还是无法容纳新的记录,NGINX返回503 (Service Temporarily Unavailable)状态码。此外,为了防止内存被耗尽,每次NGINX创建一个新的记录的同时移除多达两条前60秒内没有被使用的记录。


上述使用默认延时也就是队列的方式对于一个页面如果有很多资源需要加载,那么通过排队延时加载无疑对服务器冲击小,而且防止攻击者对同一个资源发出很多请求。
如果我们使用nodelay:
limit_req zone=one burst=10 nodelay;

这表示,如果每秒请求在5-10个之间会尽快完成,也就是以每秒10个速率完成,超过每秒10+5也就是15个就立即返回503,因此nodelay实际没有了延时,也就取消了队列等候过渡。


加上 nodelay之后超过 burst大小的请求就会直接返回503,如果没有该字段会造成大量的tcp连接请求等待。


最后一个带宽限制,如下:
limit_rate 50k;limit_rate_after 500k;
当下载的大小超过500k以后,以每秒50K速率限制。

只开一个连接:
ab -n100 -c100 -k https//www.phpmianshi.com/test.php
这里的-k选秀就是表示keepalive,只开一个连接来发送这100个请求,即使是同时发送,那么server也不会认为你超过了,因为在一个时间你只是建立一个连接,这样这100个请求都会干净利落的处理完成。

高级设置的例子
下面的例子展示了如何将限流作用在任何一个不在“白名单”中的请求上。
geo $limit {
    default 1;
    10.0.0.0/8 0;
    192.168.0.0/24 0;
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;

server {
    location / {
        limit_req zone=req_zone burst=10 nodelay;
        # ...
    }
}


这个例子同时使用了geomap指令。对于IP地址在白名单中的,geo块分配0值给$limit;其它所有不在白名单中的IP地址,分配1值。然后我们使用一个map去将这些值映射到某个key中,例如:

  • 如果$limit0$limit_key被设置为空字符串

  • 如果$limit1$limit_key被设置为客户端的IP地址的二进制格式

这个两个结合起来,对于白名单中的IP地址,$limit_key被设置为空字符串;否则,被设置为客户端的IP地址。当limit_req_zone指令的第一个参数是一个空字符串,限制不起作用,因此白名单的IP地址(在10.0.0.0/8和192.168.0.0/24子网中)没有被限制。其它所有的IP地址都被限制为5个请求每秒。


超过限流的请求会返回503

查看nginx的错误日志如下:

 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

linux下utf-8 BOM的检查和删除

背景当源程序是gbk格式,你转换为 utf8 的时候,很多情况是头部会出现bom,当是php 程序时候,这样会出现很多意想不到的事情,那怎么办呢,你可以用linux 命令来查找,然后对文件的bom 进...

linux中配置内核参数sysctl详解

概念sysctl用于运行时配置内核参数,这些参数位于/proc/sys目录下。sysctl配置与显示在/proc/sys目录中的内核参数。用户只需要编辑/etc/sysctl.conf文件,即可手工或...

linux中高并发场景下too many open files问题处理

概述:高并发场景下 too many open files 问题。可以通过设置系统打开文件数,直接影响单个进程容纳的客户端连接数。比如会影响到长链接应用如聊天中单个进程能够维持的用户连接数, 运行ul...

linux中查看系统活动情况报告sar命令详解

有很多工具可以看网络流量,但我最喜欢sar。sar(System Activity Reporter系统活动情况报告)是目前 Linux 上最为全面的系统性能分析工具之一,可以从多...

记一次laravel项目因opcache导致的include过慢问题

问题表现 php-fpm-slow.log 大量如下日志:script_filename = /data/nginx/webroot/app-20200611-160330-feb...

HTTP状态码302、303和307的前世今生

背景《HTTP权威指南》第3章在讲解30X状态码时,完全没有讲清楚为什么要有302、303、307,以及他们的关系,一句“问题出在HTTP1.1”;而第五章在讲重定向响应时,没有说到现在很常见的302...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。