相信不少人都被CC过,我也不例外,因此一直以来想尽各种办法降低PHP所占的资源。
PHP所耗的资源算压下去了,带宽却满了……
之前也看过有人使用Nginx的第三方模块limit req2实现防CC攻击,自己也弄过,但效果没想象中的好,只用了几十分钟我就抛弃了……
昨天其中考试结束后,突然灵机一动,想到一个新的防CC方法。回家后经过多次调试,几经完善,已经基本能正常使用了。
这其中利用了Nginx的日志功能,还有自己写的一个Shell Script。本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
Apache的请移步这里:Apache:只有访客IP的日志格式
首先给Nginx添加一个只有访客IP的日志格式,在nginx.conf的http层加入以下代码:
1 |
log_format iponly '$remote_addr'; |
重启nginx,就会多一个名为iponly的日志格式。本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
顺便提一下:$remote_addr是HTTP请求头,此变量包含访客真实IP地址。更详细的介绍请移步:多重代理时如何防止伪造X-Forwarded-For且获取真实IP
然后修改需要开启防CC的网站配置文件,在server层加入以下代码:
1 |
access_log /var/log/nginx/iponly.log iponly; |
除非nginx对日志目录有写入权限,否则要把这一步也执行了:
1 |
touch /var/log/nginx/iponly.log |
然后重启nginx,这样该站点就会多一个只记录访客IP的日志。其中的/var/log/nginx/iponly.log是日志的路径,可以自行更改。
刷新一下网站,看看日志文件里面有没有出现真实IP地址。有的话就代表一切正常。
接下来是最关键的一步,写监控该日志文件的Shell Script。本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
2013年11月24日修改,可同时封禁多个IP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#!/bin/bash #函数ban_now ban_now() { #输出IP的内容 echo $1 #执行iptables对该IP封禁 iptables -I INPUT -s $1 -p all -j DROP #封禁后执行mail命令,给指定邮箱发一封邮件 echo -e "IP:$1 was banned at $(date).\n\niptables filter tables:\n\n$(iptables -L -n -t filter)" | mail -s "IP:$1 was banned at $(date)" your@email.com } #循环的开始 while [ "$loop" = "" ] do #清空日志文件 cat>/var/log/nginx/iponly.log<<EOF EOF #延迟五秒 ping -c 5 127.0.0.1 >/dev/null 2>&1 #合并,排序IP,输出获取请求数最大的IP及其请求数,请求数与IP之间使用英文逗号隔开,然后赋值给connections connections=$(cat /var/log/nginx/iponly.log | sort -n | uniq -c | sort -nr | awk '{print $1 "," $2}') #判断变量connections是否为空 if [ "$connections" != "" ];then #输出变量connections的内容 echo $connections #连接数的for循环开始 for ipconntctions in $connections do #截取连接数 connectnumber=$(echo $ipconntctions | cut -d "," -f 1) #判断该IP连接数是否大于200 test $connectnumber -ge 200 && banit=1 #大于200,把IP赋值给变量fuckingip if [ "$banit" = "1" ];then fuckingip=$(echo $ipconntctions | cut -d "," -f 2) ban_now $fuckingip unset banit else #否则,结束for循环 break fi done fi done |
因为要该Shell Script一直执行,因此我使用while…do…done制作了一个“死循环”。
在第六行写了一个函数ban_ip(),是使用iptables对IP进行封禁,并且完成后给我的邮箱发一封邮件。标题为:“IP和封禁时间”。内容为IP封禁时间和iptables的filter表。本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
为何与200对比?经过我多次测试,发现五秒内200请求数是比较正常的。当然你可以改小或者改大一点。
保存以上代码后,赋予x(执行)权限。
要实现该Shell Script在后台类似daemon,就需要使用nohup这个东西了:
1 |
nohup 该shell script的位置 >/dev/null 2>&1 & |
>/dev/null 2>&1表示把执行该shell script所输出的信息(shell script中的几个echo,我调试是时候用的。)重定向至/dev/null里面。
最后面的&代表后台执行。本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
这样的话,即使注销了登录,该Shell Script也一样会在后台执行。
到此文章首发为止,暂未出现误封的情况:
经过多次测试,效果是不错的,但该方法也有不足:仅限于防那些单IP连接数较大的CC攻击。遇到成百上千个IP的攻击,且每IP连接数只有一两个的话,那恐怕安全宝什么的都无能为力了(貌似阿里云的云盾可以,会看到域名后面有尾巴)……本文出自微宇宙(http://zhensheng.im),转载者死一户口本。
Comments are closed.