nginx限制客户端请求数+iptables限制TCP连接和频率来防止DDOS

DDOS的特点是分布式,针对带宽和服务×××,即四层流量×××和七层应用×××。对于七层的应用×××,如果前端是Nginx,主要使用nginx的http_limit_conn和http_limit_req模块来防御,通过限制连接数和请求数能相对有效的防御CC×××。

* ngx_http_limit_req_module:限制单个IP单位时间内的请求数,即速率限制,该模块默认已经安装
* ngx_http_limit_conn_module:限制单个IP同一时间连接数,即并发连接数限制

一个TCP连接可以产生多个请求,例如,一个页面上有很多图片,对客户端来说只需要发送这个页面的一次请求,而每个图片实际对应的就是一个连接,所以实际应用中对请求做限制比对连接做限制的效果更好。


ngx_http_limit_req_module:限制每秒请求数

  • ngx_http_limit_req_module模块通过漏桶原理来限制单位时间内的请求数,一旦单位时间内请求数超过限制,就会返回503错误。
  • ngx_http_limit_req_module模块有2部分:
* http字段中定义触发条件,可以有多个条件;
* http、server、location段中定义达到触发条件时nginx所要执行的动作。
  • http段:
    语法:limit_req_zone $variable zone=name:size rate=rate;
    实例:limit_req_zone $binary_remote_addr zone=two:100m rate=50r/s;
    说明:1、$binary_remote_addr:是$remote_addr(客户端IP)的二进制格式,固定占用4个字节,而$remote_addr按照字符串存储,占用7-15个字节,用$binary_remote_addr可以节省空间。这样1M的内存可以保存大约1万6千个64字节的记录。
    2、zone=:区域名称,可自定义,这里写的是two,分配内存空间大小为100m,,用来存储会话(二进制远程地址),如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
    3、rate=:平均处理的请求数,这里定义的是每秒不能超过每秒50次。也可以设置为每分钟处理请求数(r/m),其值必须是整数,
  • http, server, location段:
  • 1、limit_req zone
    语法: limit_req zone=name [burst=number] [nodelay];
    实例:limit_req zone=two burst=20 nodelay;
    说明:1、zone=:和http字段中limit_req_zone的zone定义必须一致
    2、burst=:可以理解为缓冲队列
    3、nodelay:对用户发起的请求不做延迟处理,而是立即处理。比如上面定义了rate=20r/s,即每秒钟只处理20个请求。如果同一时刻有22个请求过,若设置了nodelay,则会立刻处理这22个请求。若没设置nodelay,则会严格执行rate=20r/s的配置,即只处理20个请求,然后下一秒钟再处理另外2个请求。直观的看就是页面数据卡了,过了一秒后才加载出来。

例如:

[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
            limit_req_zone $binary_remote_addr zone=two:100m rate=50r/s;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_req zone=two burst=20 nodelay;
                                 ......
                                 }
        }                        
  • 对限流起作用的配置就是rate=50r/s和burst=20这两个配置,假如同一秒有55个请求到达nginx,其中50个请求被处理,另外的5个请求被放到burst缓冲队列里,由于配置了nodelay,第51-55个请求依然会被处理,但是会占用burst缓冲队列的5个长度,如果下一秒没有新的请求过来,这5个长度的空间会被释放,否则会继续占用burst缓冲队列5个长度,如果后面每秒请求都超过50个,那么多余的请求虽然会被处理但是会占用burst缓冲队列长度,直到达到设定的burst=20,后面的每秒第51个请求开始会被nginx拒绝,并返回503错误,被拒绝的请求在nginx的日志中可以看到被那个zone拒绝的。

  • 2、limit_req_log_level
    语法: limit_req_log_level info | notice | warn | error;
    默认值: limit_req_log_level error;
    配置段: http, server, location
    设置日志级别,当服务器因为频率过高拒绝或者延迟处理请求时可以记下相应级别的日志。 延迟记录的日志级别比拒绝的低一个级别; 如果设置“limit_req_log_level notice”, 延迟的日志就是info级别。

  • 3、limit_req_status
    语法: limit_req_status code;
    默认值: limit_req_status 503;
    配置段: http, server, location
    该指令在1.3.15版本引入。设置拒绝请求的响应状态码。

ngx_http_limit_conn_module:限制IP连接数

ngx_http_limit_conn_module的模块也有2部分:

* http字段中定义触发条件,可以有多个条件;
* http、server、location段中定义达到触发条件时nginx所要执行的动作。
  • http段:
    语法:limit_conn_zone key zone=name:memory_max_size;
    实例:limit_conn_zone $binary_remote_addr zone=one:10m;
    说明:limit_conn_zone模块只能配置在http字段中进行定义,该指令描述会话状态存储区域。主要用来定义变量、zone名称、共享内存大小,键的状态中保存了当前连接数,键的值可以是特定变量的任何非空值(空值不会被考虑)。size 定义各个键共享内存空间大小,如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。从Nginx 1.1.8版本后limit_conn升级为limit_conn_zone。连接数限制不是所有的连接都计算在内;只有那些已请求该服务器并当前正在处理的请求(请求头已充分阅读的)。

  • http, server, location段:
  • 1、limit_conn one
    语法:limit_conn one conn_max_num;
    实例:limit_conn one 20;
    说明:该指令指定每个给定键值的最大同时连接数,当超过这个数字时返回503(Service )错误。如(同一IP同一时间只允许有20个连接)。
[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
            limit_conn_zone  $binary_remote_addr  zone=one:10m;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_conn one 20;
                                 ......
                                 }
        }   

还可以叠加使用,同时限制访问的虚拟主机:

[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
    limit_conn_zone  $binary_remote_addr  zone=perip:100m;
    limit_conn_zone  $server_name  zone=perserver:100m;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_conn perip 50;;     #同一个IP限制链接20个
                                 limit_conn perserver 20;;   #同一主机名链接限制在100个
                                 ......
                                 }
        }   

*2、 limit_conn_log_level
语法: limit_conn_log_level info | notice | warn | error;
默认值: limit_conn_log_level error;
使用环境: http, server, location
设置触发最大限制后记录日志的级别,默认为error级别,该指令在 0.8.18版后新增

*3、 limit_conn_status
语法: limit_conn_status code;
默认值: limit_conn_status 503;
使用环境: http, server, location
当超出最大同时连接数的时候,对于新增连接返回的错误代码,默认503. 该指令在 1.3.15版本后新增,

*4、 limit_rate
语法:limit_rate rate
默认值:0
实例:limit_rate 200k;
配置段:http, server, location, if in location
对每个连接的速率限制。参数rate的单位是字节/秒,设置为0将关闭限速。 按连接限速而不是按IP限制,因此如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的2倍。


白名单设置

http_limit_conn和http_limit_req模块限制了单ip单位时间内的并发和请求数,如前端如果有做LVS或反代,对于后端的ningx来说过来的请求都是lvs或者反代的IP,而我们后端启用了该模块功能,那不是非常多503错误了?这样的话,就需要geo和map模块设置白名单:

    geo $whiteiplist  {
        default 1;
        10.15.43.18 0;
    }
    map $whiteiplist  $limit {
        1 $binary_remote_addr;
        0 "";
    }

geo模块定义了一个默认值default 1的变量$whiteiplist,当ip在白名单中,变量whiteiplist的值为0(10.15.43.18 0),反之为1
如果在白名单中--> whiteiplist=0 --> $limit="" --> 不会存储到zone对应的内存共享会话状态中 --> 不受限制
反之,不在白名单中 --> whiteiplist=1 --> $limit=二进制远程地址 -->存储进zone对应的内存共享会话状态中 --> 受到限制

iptables设置

单个IP在60秒内只允许新建20个连接访问web的80端口
iptables -I  INPUT -i eth1 -p tcp -m tcp –dport 80 -m state –state NEW -m recent –update –seconds 60 –hitcount 20 –name DEFAULT –rsource -j DROP
iptables -I  INPUT -i eth1 -p tcp -m tcp –dport 80 -m state –state NEW -m recent –set –name DEFAULT –rsource

单个IP的最大并发连接数为20
iptables  -I INPUT -p tcp –dport 80 -m connlimit  –connlimit-above 20 -j REJECT  

每个IP最多20个初始连接
iptables -I  INPUT -p tcp –syn -m connlimit –connlimit-above 20 -j DROP

测试

使用ab命令来模拟CC×××,http_limit_conn和http_limit_req模块要分开测试,同时注意http_limit_conn模块只统计正在被处理的请求(这些请求的头信息已被完全读入)所在的连接。如果请求已经处理完,连接没有被关闭时,是不会被统计的。这时用netstat看到连接数可以超过限定的数量,不会被阻止。

http {
    ......
    geo $whiteiplist  {
        default 1;
        10.15.43.18 0;
    }
    map $whiteiplist  $limit {
        1 $binary_remote_addr;
        0 "";
    }
    limit_req_zone $binary_remote_addr zone=one:100m rate=50r/s;
    limit_conn_zone $binary_remote_addr zone=two:10m;
    limit_conn_zone $server_name zone=three:10m;    
......  
   server {
        listen       80;
        server_name  192.168.100.127;
        ......
        server_tokens off;
        limit_req zone=one burst=20 nodelay;
        limit_req_log_level error;
        limit_req_status 503;
        limit_conn two 20;
        limit_conn three 3;
        limit_conn_log_level error;
        limit_conn_status 503;
        limit_rate 200k;
        ......

        location / {
            root   html;
            index  index.html index.htm;
        }
        ......
}   
  • Web网站压力测试工具ab(apache benchmark)

ab是针对apache的性能测试工具,在APACHE的bin目录下,也可以只安装ab工具。

[root@localhost ~]# yum install -y httpd-tools
[root@localhost ~]# ab -V
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
[root@localhost ~]# ab -v
ab: option requires an argument -- v
ab: wrong number of arguments
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     Number of requests to perform       #在测试会话中所执行的请求次数。默认时,仅执行一个请求
    -c concurrency  Number of multiple requests to make at a time        #一次产生的请求个数,即并发数。默认是一次一个
    -t timelimit    Seconds to max. to spend on benchmarking    #测试所进行的最大秒数。其内部隐含值是-n 50000。它可以使对服务器的测试限制在一个固定的总时间以内。默认时,没有时间限制。
                    This implies -n 50000
    -s timeout      Seconds to max. wait for each response
                    Default is 30 seconds
    -b windowsize   Size of TCP send/receive buffer, in bytes
    -B address      Address to bind to when making outgoing connections
    -p postfile     File containing data to POST. Remember also to set -T           #包含了需要POST的数据的文件. 
    -u putfile      File containing data to PUT. Remember also to set -T
    -T content-type Content-type header to use for POST/PUT data, eg.              #POST数据所使用的Content-type头信息。
                    'application/x-www-form-urlencoded'
                    Default is 'text/plain'
    -v verbosity    How much troubleshooting info to print   #设置显示信息的详细程度 - 4或更大值会显示头信息, 3或更大值可以显示响应代码(404, 200等), 2或更大值可以显示警告和其他信息。 -V 显示版本号并退出。
    -w              Print out results in HTML tables         #以HTML表的格式输出结果。默认时,它是白色背景的两列宽度的一张表。
    -i              Use HEAD instead of GET              #执行HEAD请求,而不是GET
    -x attributes   String to insert as table attributes
    -y attributes   String to insert as tr attributes
    -z attributes   String to insert as td or th attributes
    -C attribute    Add cookie, eg. 'Apache=1234'. (repeatable)      #-C cookie-name=value 对请求附加一个Cookie:行。 其典型形式是name=value的一个参数对。此参数可以重复。
    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
                    Inserted after all normal header lines. (repeatable)
    -A attribute    Add Basic WWW Authentication, the attributes
                    are a colon separated username and password.
    -P attribute    Add Basic Proxy Authentication, the attributes               
                    are a colon separated username and password.       #-P proxy-auth-username:password 对一个中转代理提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形式发送。无论服务器是否需要(即, 是否发送了401认证需求代码),此字符串都会被发送。
    -X proxy:port   Proxyserver and port number to use
    -V              Print version number and exit
    -k              Use HTTP KeepAlive feature
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -q              Do not show progress when doing more than 150 requests
    -g filename     Output collected data to gnuplot format file.
    -e filename     Output CSV file with percentages served
    -r              Don't exit on socket receive errors.
    -h              Display usage information (this message)
    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)
    -f protocol     Specify SSL/TLS protocol
                    (SSL3, TLS1, TLS1.1, TLS1.2 or ALL)
root@localhost ~]# ab -n1000 -c10 http://192.168.100.127/index.html      #同时处理10个请求,连续1000次
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.100.127 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        openresty             #测试的Web服务器软件名称
Server Hostname:        192.168.100.127      #服务器主机名
Server Port:            80

Document Path:          /index.html
Document Length:        6110 bytes

Concurrency Level:      10     #并发数
Time taken for tests:   0.255 seconds          #整个测试持续的时间
Complete requests:      1000          #完成的请求数量
Failed requests:        967                 #失败的请求数量
   (Connect: 0, Receive: 0, Length: 967, Exceptions: 0)
Write errors:           0
Non-2xx responses:      967
Total transferred:      917130 bytes                 #整个场景中的网络传输量
HTML transferred:       724777 bytes           #整个场景中的HTML内容传输量
Requests per second:    3917.94 [#/sec] (mean)           #吞吐率,重要指标之一,相当于 LR 中的 每秒事务数 ,后面括号中的 mean 表示这是一个平均值
Time per request:       2.552 [ms] (mean)    #用户平均请求等待时间,重要指标之二,相当于 LR 中的 平均事务响应时间
Time per request:       0.255 [ms] (mean, across all concurrent requests)    #服务器平均请求处理时间,重要指标之三
Transfer rate:          3509.05 [Kbytes/sec] received         #平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题

Connection Times (ms)             #网络上消耗的时间的分解
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    2   0.7      2       5
Waiting:        1    2   0.7      2       5
Total:          1    2   0.7      2       5

Percentage of the requests served within a certain time (ms)              #每个请求处理时间的分布情况
  50%      2
  66%      3
  75%      3
  80%      3
  90%      3
  95%      5
  98%      5
  99%      5
 100%      5 (longest request)
 #整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间,其中50%的用户响应时间小于2 毫秒,66% 的用户响应时间小于3毫秒,最大的响应时间小于5 毫秒
[root@localhost ~]# 
  1. 吞吐率(Requests per second)
    概念:服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。
    计算公式:总请求数 / 处理完成这些请求数所花费的时间,即
    Request per second = Complete requests / Time taken for tests

  2. 并发连接数(The number of concurrent connections)
    概念:某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。

  3. 并发用户数(The number of concurrent users,Concurrency Level)
    概念:要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。

  4. 用户平均请求等待时间(Time per request)
    计算公式:处理完成所有请求数所花费的时间/ (总请求数 / 并发用户数),即
    Time per request = Time taken for tests /( Complete requests / Concurrency Level)

  5. 服务器平均请求等待时间(Time per request: across all concurrent requests)
    计算公式:处理完成所有请求数所花费的时间 / 总请求数,即
    Time taken for / testsComplete requests
    可以看到,它是吞吐率的倒数。
    同时,它也=用户平均请求等待时间/并发用户数,即
    Time per request / Concurrency Level

Webbench是知名的网站压力测试工具,它是由Lionbridge公司开发。它能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况。能够统计每秒钟相应请求数和每秒钟传输数据量。webbench既能测试静态页面,还能对动态页面(ASP,PHP,JAVA,CGI)进 行测试。还支持对含有SSL的安全网站进行静态或动态的性能测试。最多可以模拟3万个并发连接去测试网站的负载能力。
官网:http://home.tiscali.cz/~cz210552/webbench.html
webbench会fork出多个子进程,每个子进程都循环做web访问测试。子进程把访问的结果通过pipe告诉父进程,父进程做最终的统计结果

[root@localhost soft]# yum install ctags wget make apr* autoconf automake gcc gcc-c++
[root@localhost soft]# wget http://home.tiscali.cz/cz210552/distfiles/webbench-1.5.tar.gz
[root@localhost soft]# tar -zxvf webbench-1.5.tar.gz
[root@localhost soft]# cd webbench-1.5
[root@localhost webbench-1.5]# make
[root@localhost webbench-1.5]# make install  #这步可能提示/usr/local/man不存在,如果存在检查权限
[root@localhost webbench-1.5]# which webbench
/usr/local/bin/webbench
[root@localhost webbench-1.5]# webbench --help
webbench [option]... URL
  -f|--force               Don't wait for reply from server.     #不需要等待服务器相应
  -r|--reload              Send reload request - Pragma: no-cache.    #不发送重新加载请求
  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.    #运行测试持续时间,单位秒
  -p|--proxy <server:port> Use proxy server for request.   #使用代理服务器发送请求
  -c|--clients <n>         Run <n> HTTP clients at once. Default one.   #执行并发客户端数量,默认1个
  -9|--http09              Use HTTP/0.9 style requests.    #使用http/0.9
  -1|--http10              Use HTTP/1.0 protocol.       #使用HTTP/1.0协议
  -2|--http11              Use HTTP/1.1 protocol.       
  --get                    Use GET request method.     
  --head                   Use HEAD request method.
  --options                Use OPTIONS request method.
  --trace                  Use TRACE request method.
  -?|-h|--help             This information.
  -V|--version             Display program version.
[root@localhost webbench-1.5]# webbench -c 10 -t 30 http://192.168.100.127
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Invalid URL syntax - hostname don't ends with '/'.
[root@localhost webbench-1.5]# webbench -c 10 -t 30 http://192.168.100.127/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://192.168.100.127/
10 clients, running 30 sec.

Speed=245980 pages/min, 26000094 bytes/sec.    #每秒钟响应请求数:245980 pages/min,每秒钟传输数据量26000094 bytes/sec.
Requests: 122990 susceed, 0 failed.       #122990次返回成功,0次返回失败
[root@localhost soft]# cat webbench.sh 
#!/bin/bash
export LANG="en_US.UTF-8"
#export LANG="zh_CN.UTF8"
source /etc/rc.d/init.d/functions
[ -f /etc/profile ] && . /etc/profile
[ -f ~/.bash_profile ] && . ~/.bash_profile
for n in `seq 5 5 50`;do 
   echo -n $n " " 
   webbench -c $n -t 60 http://192.168.100.127/ 2>/dev/null | grep Speed | awk '{print $1}' | awk -F= '{print $2}' 
   echo 
done
[root@localhost soft]#
  • webbench的优点:
    1.部署简单,适用于小型网站压力测试,(最多可模拟3万并发);
    2.它具有静态页面测试能力也支持动态页面(ASP,PHP,JAVA,CGI)进行测试能力;
    3.支持对含有SSL的安全网站如电子商务网站进行动态或静态性能测试;

  • webbench的缺点:
    1.不适合中大型网站测试;
    2.其并发采用多进程实现并非线程,长时间其会大量占用内存与CPU,所以一般长时间的压力测试不推荐使用webbench.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值