Nginx配置实战:访问控制及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;
默认值: 无
作用域:http, server, location, limit_except
禁止某个 IP 或者一个 IP 段访问。如果指定 unix,那将禁止 socket 的访问。
配置范例:
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all;
}
规则按照顺序依次检测,直到匹配到第一条规则。
在这个例子里,IPv4 的网络中只有 10.1.1.0/16 和 192.168.1.0/24 允许访问,但 192.168.1.1 除外;对于 IPv6 的网络,只有 2001:0db8::/32 允许访问。
ngx_http_access_module
配置允许的地址能访问,禁止的地址被拒绝。
这只是很简单的访问控制,而在规则很多的情况下,使用
ngx_http_geo_module
模块变量更合适。这里的
ngx_http_geo_module
模块大家下来可以了解 : ngx_http_geo_module
DDoS 预防配置
DDoS 的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构的吞吐量。
对于七层的应用攻击,我们还是可以做一些配置来防御的,使用 Nginx 的 http_limit_conn 和 http_limit_req 模块通过限制连接数和请求数能相对有效的防御。
ngx_http_limit_conn_module:可以限制单个 IP 的连接数
ngx_http_limit_req_module:可以限制单个 IP 每秒请求数
限制每秒请求数
ngx_http_limit_req_module 模块通过漏桶原理来限制单位时间内的请求数,一旦单位时间内请求数超过限制,就会返回 503 错误。配置需要在两个地方设置:
nginx.conf 的 http 段内定义触发条件,可以有多个条件
在 location 内定义达到触发条件时 nginx 所要执行的动作
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
...
server {
...
location ~ \.php$ {
limit_req zone=one burst=5 nodelay;
}
}
}
参数说明
限制 IP 连接数
上一章讲过,我们就直接写出来
http {
limit_conn_zone $binary_remote_addr zone=addr:10m; //触发条件
...
server {
...
location /download/ {
limit_conn addr 1; // 限制同一时间内1个连接,超出的连接返回503
}
}
}
白名单设置
http_limit_conn 和 http_limit_req 模块限制了单 IP 单位时间内的连接和请求数,但是如果 Nginx 前面有 lvs 或者 haproxy 之类的负载均衡或者反向代理,nginx 获取的都是来自负载均衡的连接或请求,这时不应该限制负载均衡的连接和请求,就需要 geo 和 map 模块设置白名单:
geo $whiteiplist {
default 1;
10.11.15.161 0;
}
map $whiteiplist $limit {
1 $binary_remote_addr;
0 "";
}
limit_req_zone $limit zone=one:10m rate=10r/s;
limit_conn_zone $limit zone=addr:10m;
geo 模块定义了一个默认值是 1 的变量 whiteiplist,当在 ip 在白名单中,变量 whiteiplist 的值为 0,反之为 1
下面是设置的逻辑关系解释:
如果在白名单中--> whiteiplist=0 --> limit=二进制远程地址 -->存储进 10m 的会话状态中 --> 受到限制。
安装所有测试所需的软件
安装 php7.0-fpm 和 apache2-utils
sudo apt-get update
sudo apt-get install apache2-utils
sudo apt-get install php7.0-fpm
安装好以后 分别启动 php 和 nginx。
sudo service nginx start
sudo service php7.0-fpm start
测试访问
写一个测试的 php 文件,修改 nginx 配置文件,使其能正常访问。
在 /var/www/html 目录下写一个 test.php,内容如下:
<?php
phpinfo();
?>
如果显示 404 notfound 则是因为之前配置过端口号 9000,在访问时输入 localhost:9000/test.php 即可。后文同理。
修改配置
修改/etc/nginx/nginx.conf
http {
##
# Basic Settings
##
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; # 加入这行
....
....
修改 /etc/nginx/sites-available/default
location ~ \.php$ {
limit_req zone=one burst=5 nodelay; # 加入这行
root /var/www/html;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
测试
修改配置文件后,使用命令 ab 测试。
ab -n 10 -c 10 http://localhost/test.php
其中 -n 代表每次并发量,-c 代表总共发送的数量。这条命令表示 10 个请求一次并发出去。
测试结果:
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: nginx/1.10.3
Server Hostname: localhost
Server Port: 80
Document Path: /test.php
Document Length: 16 bytes
Concurrency Level: 10
Time taken for tests: 0.051 seconds
Complete requests: 10
Failed requests: 0
Non-2xx responses: 10
Total transferred: 1690 bytes
HTML transferred: 160 bytes
Requests per second: 197.01 [#/sec] (mean)
Time per request: 50.760 [ms] (mean)
Time per request: 5.076 [ms] (mean, across all concurrent requests)
Transfer rate: 32.51 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.7 0 5
Processing: 10 34 14.9 45 45
Waiting: 10 34 14.9 45 45
Total: 15 35 14.0 45 45
Percentage of the requests served within a certain time (ms)
50% 45
66% 45
75% 45
80% 45
90% 45
95% 45
98% 45
99% 45
100% 45 (longest request)
然后我们查看 log,可以看出我们并发了 10 条请求,有 4 条访问失败。
sudo tail /var/log/nginx/error.log
2019/09/17 14:00:11 [error] 8446#8446: *23 limiting requests, excess: 6.000 by zone "one", client: 127.0.0.1, server: _, request: "GET /test.php HTTP/1.0", host: "localhost"
2019/09/17 14:00:11 [error] 8446#8446: *24 limiting requests, excess: 6.000 by zone "one", client: 127.0.0.1, server: _, request: "GET /test.php HTTP/1.0", host: "localhost"
2019/09/17 14:00:11 [error] 8446#8446: *25 limiting requests, excess: 6.000 by zone "one", client: 127.0.0.1, server: _, request: "GET /test.php HTTP/1.0", host: "localhost"
2019/09/17 14:00:11 [error] 8446#8446: *26 limiting requests, excess: 6.000 by zone "one", client: 127.0.0.1, server: _, request: "GET /test.php HTTP/1.0", host: "localhost"
........
挑战:访问控制
介绍
编写一个 Nginx 的 access 模块配置,要求如下:
准许 192.168.3.29/24 的机器访问
准许 10.1.20.6/16 这个网段的所有机器访问
准许 34.26.157.0/24 这个网段访问
除此之外的机器不准许访问
参考配置
在 /etc/nginx/nginx.conf 中加入如下配置:
http {
......
server {
location / {
allow 192.168.3.29/24;
allow 10.1.20.6/16;
allow 34.26.157.0/24;
deny all;
}
}
......
}