Webench是一款轻量级的网站测压工具,最多可以对网站模拟3w左右的并发请求,可以控制时间、是否使用缓存、是否等待服务器回复等等,且对中小型网站有明显的效果,基本上可以测出中小型网站的承受能力。
WebBench官网:http://home.tiscali.cz/~cz210552/webbench.html
测试环境说明:需要有两台服务器(A和B),在A服务器上上安装WebBench工具,对B服务器的网站进行测试。
注意:WebBench只支持http,不支持https
WebBench安装
yum install -y gcc ctags
wget http://file.884358.com/linux/webbench-1.5.tar.gz
tar zxvf webbench-1.5.tar.gz
cd webbench-1.5
make && make install
WebBench使用
webbench -c 100 -t 60 http://test.domain.com/phpinfo.php
webbench -c 并发数 -t 运行测试时间(秒) URL
通过测试,在A服务器执行webbench命令后,B服务器的CPU飙升至90%,同时B服务器操作卡顿,B服务器上的网站也打不开了。通过观察nignx日志,发现大量的并发请求:
如何防止短时间的大量并发导致服务器宕机。
解决办法:
控制并发数,控制请求频率,必要时fail2ban
控制并发数及请求频率
修改nginx配置,做如下设置:
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接
## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了
limit_conn_zone $binary_remote_addr zone=TotalConnLimitZone:10m ;
limit_conn TotalConnLimitZone 50;
limit_conn_log_level notice;
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求
## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你
limit_req_zone $binary_remote_addr zone=ConnLimitZone:10m rate=10r/s;
limit_req_log_level notice;
## 具体服务器配置
server {
listen 80;
location ~ \.php$ {
## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了
limit_req zone=ConnLimitZone burst=5 nodelay;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}
}
重启nginx,重新进行测试,测试结果发现A服务器的请求响应都变成了503:
说明在nginx层面,已经拒绝了大量的并发请求。但尽管如此,服务器的CPU依然占用很高,网站依然打开缓慢。
安装fail2ban
检查Firewalld是否启用
firewall-cmd --state
fail2ban可以监控系统日志,并且根据一定规则匹配异常IP后使用Firewalld将其屏蔽,尤其是针对一些爆破/扫描等非常有效。
yum -y install fail2ban
安装成功后fail2ban配置文件位于/etc/fail2ban,其中jail.conf为主配置文件,相关的匹配规则位于filter.d目录,其它目录/文件一般很少用到,如果需要详细了解可自行搜索。
配置规则
新建jail.local来覆盖fail2ban的一些默认规则:
#新建配置
vi /etc/fail2ban/jail.local
#默认配置
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 86400
findtime = 600
maxretry = 5
#这里banaction必须用firewallcmd-ipset,这是fiewalll支持的关键,如果是CentOS6,只有iptables那么填写:iptables-multiport
banaction = firewallcmd-ipset
action = %(action_mwl)s
- ignoreip:IP白名单,白名单中的IP不会屏蔽,可填写多个以(,)分隔
- bantime:屏蔽时间,单位为秒(s)
- findtime:时间范围
- maxretry:最大次数
- banaction:屏蔽IP所使用的方法,上面使用firewalld屏蔽端口
监控nginx访问日志
这里仅以Nginx为例,使用fail2ban来监视nginx日志,匹配短时间内频繁请求的IP,并使用firewalld将其IP屏蔽,达到CC防护的作用。
#需要先新建一个nginx日志匹配规则
vi /etc/fail2ban/filter.d/nginx-cc.conf
#填写如下内容
[Definition]
failregex = <HOST> -.*- .*HTTP/[12].* .* .*$
ignoreregex =
继续修改vi /etc/fail2ban/jail.local追加如下内容:
[nginx-cc]
enabled = true
port = http,https
filter = nginx-cc
action = %(action_mwl)s
maxretry = 20
findtime = 60
bantime = 3600
logpath = /usr/local/nginx/logs/access.log
上面的配置意思是如果在60s内,同一IP达到20次请求,则将其IP ban 1小时,上面只是为了测试,请根据自己的实际情况修改。logpath为nginx日志路径。
常用命令
#启动
systemctl start fail2ban
#停止
systemctl stop fail2ban
#开机启动
systemctl enable fail2ban
#查看被ban IP,其中nginx-cc为名称
fail2ban-client status nginx-cc
#删除被ban IP
fail2ban-client set nginx-cc unbanip 192.168.111.111
#添加要ban的IP
fail2ban-client set nginx-cc banip 192.168.111.111
#查看日志
tail /var/log/fail2ban.log
#查看在fail2ban黑名单里的IP是否已经加到了firewall中。
ipset list
如果启动fail2ban报错
如果是在centos6.5上,启动fail2ban时有可能会报错,例如:
有可能你升级过python的版本导致的,需要修改/usr/bin/fail2ban-client
和/usr/bin/fail2ban-server
这两个文件的第一行
不起作用原因
正常情况,按照默认设置,如果我们一分钟内访问20次网页,就会被拉入黑名单,不允许访问了,如果经测试发现不起作用,可以通过如下办法来测试
测试匹配规则
通过如下命令可以测试日志的匹配规则是否被命中
fail2ban-regex /usr/local/nginx/logs/access.log /etc/fail2ban/filter.d/nginx-cc.conf
检查fail2ban-python
ll /usr/bin/ | grep fail2ban
通过以上截图可以看到fail2ban-python
是软链接到/usr/bin/python
程序的,如果你是centos6.5且自己升级过python,那么需要重新设置下软链接
重新设置软链接
rm -rf /usr/bin/fail2ban-python
ln -s /usr/bin/python2.6 /usr/bin/fail2ban-python
使用CDN后获取真实IP地址
使用CDN后,通过日志可以看到IP都不是真实的,二是CDN的IP地址,如果继续屏蔽IP,只会把CDN的IP给屏蔽掉,而我们希望获取的是真实的IP地址。
修改nginx配置文件,在http模块中添加如下代码:
## 获取用户真实IP
log_format main '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" ';
然后在每个站点的配置文件中,在access_log后面加上main
参数。例如宝塔的nginx站点配置文件是在:
/www/server/panel/vhost/nginx/xxx.conf
那么需要打开站点配置文件,在里面的access_log后面加上main
参数。例如:
access_log /www/wwwlogs/xxx.log main;
同时,还需要修改之前的控制并发数及请求频率参数:
## 这里取得原始用户的IP地址
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}
## 针对原始用户 IP 地址做限制
limit_conn_zone $clientRealIp zone=TotalConnLimitZone:10m ;
limit_conn TotalConnLimitZone 50;
limit_conn_log_level notice;
## 针对原始用户 IP 地址做限制
limit_req_zone $clientRealIp zone=ConnLimitZone:10m rate=10r/s;
#limit_req zone=ConnLimitZone burst=10 nodelay; #如果开启此条规则,burst=10的限制将会在nginx全局生效
limit_req_log_level notice;
重启nginx,然后再次观察日志文件,可以看到记录的IP是真实的IP了。
参考文章:
Nginx在CDN加速之后,获取用户真实IP做并发访问限制的方法:https://zhang.ge/4879.html
CentOS 7安装fail2ban + Firewalld防止爆破与CC攻击:https://www.xiaoz.me/archives/9831