nginx控制模块探究、流量、并发连接数限制、访问控制及ddos预防

Nginx的优势

1、轻量级 安装文件小 运行时CPU内存使用率低

2、性能强 支持多核,处理静态文件效率高,内核采用的poll模型最大可以支持50K并发连接

3、支持热部署 同时启动速度快,可以在不间断服务的情况下对软件和配置进行升级

4、负载均衡 支持容错和健康检查

5、代理功能强大 支持无缓存的反向代理,同时支持IMAP/POP3/SMTP的代理

一、流量限制

流量及并发连接数限制主要运用Nginx的limit_rate 和 limit_rate_after命令

语法: limit_rate rate;

默认值: limit_rate 0;

作用域: http, server, location, if in location

命令概述:限制向客户端传送响应的速率限制。参数 rate 的单位是字节/秒,设置为 0 将关闭限速。 nginx 按连接限速,所以如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的 2 倍。

limit_rate_after

语法: limit_rate_after size;

默认值: limit_rate_after 0;

作用域:http, server, location, if in location

设置不限速传输的响应大小。当传输量大于此值时,超出部分将限速传送。

二、实现并发连接数限制的具体配置


此配置是基于 ngx_http_limit_zone_module 模块的,要简单完成并发限制,我们要涉及到 limit_conn_zone 和 limit_conn 这两个指令:

limit_conn_zone

语法: limit_conn_zone zone_name $variable the_size

默认值: no

作用域: http

本指令定义了一个数据区,里面记录会话状态信息。 variable 定义判断会话的变量;the_size 定义记录区的总容量。

limit_conn

语法: limit_conn zone_name the_size

默认值: no

作用域: http, server, location

指定一个会话最大的并发连接数。 当超过指定的最发并发连接数时,服务器将返回 "Service unavailable" (503)

http { 
    #写在http中   
    limit_conn_zone   $binary_remote_addr  zone=perip:10m;

    server {

        location /seven/ {            
            limit_conn  perip  1;

        }
 }

解释:定义一个叫peripp的记录区,总容量为10M,以变量$binary_remote_addr作为会话的判断基准(即一个地址一个会话)。限制目录下,一个会话只能进行一个连接。 简单点,就是限制 /seven/ 目录下,一个 IP 只能发起一个连接,多过一个,一律 503。

你可以注意到了,在这里使用的是$binary_remote_addr 而不是 $remote_addr。$remote_addr 的长度为 7 至 15 bytes,会话信息的长度为 32 或 64 bytes。 而 $binary_remote_addr 的长度为 4 bytes,会话信息的长度为 32 bytes。 当 zone 的大小为 1M 的时候,大约可以记录 32000 个会话信息(一个会话占用 32 bytes)

三、访问控制及DDOS预防

基于各种原因,我们要进行访问控制。比如说,一般网站的后台都不能让外部访问,所以要添加 IP 限制,通常只允许公司的 IP 访问。访问控制就是指只有符合条件的 IP 才能访问到这个网站的某个区域。

涉及模块:ngx_http_access_module

模块概述:允许限制某些 IP 地址的客户端访问。

对应指令:

allow

语法: allow address | CIDR | unix: | all;

默认值: —

作用域: http, server, location, limit_except

允许某个 IP 或者某个 IP 段访问。如果指定 unix,那将允许 socket 的访问。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比这个低,请不要使用这个方法。


deny

语法: deny address | CIDR | unix: | all;

默认值: 1

作用域: http, server, location, limit_except

禁止某个 IP 或者一个 IP 段访问。如果指定 unix,那将禁止 socket 的访问。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比这个低,请不要使用这个方法

location / {    
    deny192.168.1.2;    
    allow192.168.1.0/20;    
    allow10.1.1.0/20;      
    deny  all;
}

规则按照顺序依次检测,直到匹配到第一条规则。 在这个例子里,IPv4 的网络中只有 10.1.1.0/20 和 192.168.1.0/20 允许访问,但 192.168.1.2 除外;

ngx_http_access_module 配置允许的地址能访问,禁止的地址被拒绝。这只是很简单的访问控制,而在规则很多的情况下,使用 ngx_http_geo_module 模块变量更合适

DDOS 的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构的吞吐量。对于七层的应用攻击,我们还是可以做一些配置来防御的,使用 nginx 的 http_limit_conn 和 http_limit_req 模块通过限制连接数和请求数能相对有效的防御。

ngx_http_limit_conn_module 可以限制单个 IP 的连接数

ngx_http_limit_req_module 可以限制单个 IP 每秒请求数

配置方法:

(1). 限制每秒请求数

涉及模块:ngx_http_limit_req_module

通过漏桶原理来限制单位时间内的请求数,一旦单位时间内请求数超过限制,就会返回 503 错误。

http {    
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    server {

        location  ~ \.php$ {  
             
            limit_req zone=one burst=5 nodelay;  
            
               }
           }
     }

$binary_remote_addr 二进制远程地址

rate=10r/s; 限制频率为每秒 10 个请求

burst=5 允许超过频率限制的请求数不多于 5 个,假设 1、2、3、4 秒请求为每秒 9 个,那么第 5 秒内请求 15 个是允许的;反之,如果第一秒内请求 15 个,会将 5 个请求放到第二秒,第二秒内超过 10 的请求直接 503,类似多秒内平均速率限制。

nodelay 超过的请求不被延迟处理,设置后 5(不延时)+10(延时)个请求在 1 秒内处理。(这只是理论数据,最多的情况)

(2).限制 IP 连接数

http {    
    limit_conn_zone $binary_remote_addr zone=addr:10m; //上面讲过

    server {
        ...
        location /操作目录/ {  
              
            limit_conn addr 1;   
            
                }
           }
     }

(3).白名单设置

http_limit_conn 和 http_limit_req 模块限制了单 IP 单位时间内的连接和请求数,但是如果 Nginx 前面有 lvs 或者 haproxy 之类的负载均衡或者反向代理,nginx 获取的都是来自负载均衡的连接或请求,这时不应该限制负载均衡的连接和请求,就需要 geo 和 map 模块设置白名单

geo $whiteiplist {
        default 1;        
        10.11.15.1610;
    }
map $whiteiplist$limit {        
        1$binary_remote_addr;        
        0"";
    }
  limit_req_zone $limit zone=perip:10m rate=10r/s;
  limit_conn_zone $limit zone=addr:10m;

geo 模块定义了一个默认值是 1 的变量 whiteiplist,当在 ip 在白名单中,变量 whiteiplist 的值为 0,反之为 1

下面是设置的逻辑关系解释:

如果在白名单中--> whiteiplist=0 --> $limit="" --> 不会存储到 10m 的会话状态(one 或者 addr)中 --> 不受限制;

反之,不在白名单中 --> whiteiplist=1 --> $limit=二进制远程地址 -->存储进 10m 的会话状态中 --> 受到限制。