对于web服务器来说,出现最普遍的问题就是网站访问慢甚至访问不到,到服务器上查看后得出的结论是,这个网站被CC攻击了。什么是CC攻击?CC攻击属于DDos攻击的一种,攻击者会利用大量被劫持的“肉鸡”对攻击目标网站发起请求,并且频率很快,这样会导致目标网站的服务器承受不住请求压力而瘫痪。
CC攻击虽然看起来跟正常的访问没有什么区别,但如果我们仔细分析访问日志还是可以找到一些线索,比如某个IP访问频次很高,或者某几个IP的user_agent是固定的等等特性,有的甚至会去模仿正规的搜索引擎,比如,把自己伪装成百度的“蜘蛛爬虫”。当遇到CC攻击时,只要你肯花费一些精力来分析访问日志,终究是可以找到发起CC攻击的真凶,然后封掉他们的IP就行了。
本案例就是要自动封IP和解IP,具体需求如下:
1)每分钟分析一次访问日志 /data/logs/access_log ,日志片段如下: 50.118.255.36 - - [20/Dec/2018:12:42:04 +0800] "GET http://www.sbjudge2.com/azenv.php HTTP/1.1" 301 178 "-" "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; Trident/5.0)" 111.206.198.31 - - [20/Dec/2018:12:46:57 +0800] "GET /content/uploads/2018/10/%E5%A4%87%E6%A1%88%E5%9B%BE%E6%A0%87.png HTTP/1.1" 200 509 "https://www.lzxlinux.com/archives/tag/%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4/" "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)" 111.121.113.93 - - [20/Dec/2018:13:02:34 +0800] "GET /archives/80365/ HTTP/1.1" 200 11059 "https://www.google.com.hk/" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Safari/537.36 MZBrowser/7.9.4" 2)把访问量高于100的IP封掉; 3)封过的IP都要记录到一个日志文件中; 4)每隔30分钟检查一次被封的IP,把没有请求或者请求很少的IP解封; 5)解封的IP记录到另外一个日志文件中。
参考脚本如下:
#!/bin/bash#把访问量很大的IP封掉,如果30分钟内被封IP的请求几乎没有就解封IP#定义1分钟以前的时间,用于过滤1分钟以前的日志t1=`date -d "-1 min" +%Y:%H:%M`log=/data/logs/access_log block_ip(){ egrep "$t1:[0-5]+" $log > /tmp/tmp_last_min.log #把1分钟内访问量高于100的IP记录到一个临时文件中 awk '{print $1}' /tmp/tmp_last_min.log |sort -n |uniq -c |sort -n |awk '$1>100 {print $2}' > /tmp/bad_ip.list #计算IP的数量 n=`wc -l /tmp/bad_ip.list |awk '{print $1}'` #当ip数大于0时,才会用iptables封掉它 if [ $n -ne 0 ];then for ip in `cat /tmp/bad_ip.list` do iptables -I INPUT -s $ip -j REJECT done #将这些被封IP记录到日志里 echo "`date` 封掉的IP有:" >> /tmp/block_ip.log cat /tmp/bad_ip.list >> /tmp/block_ip.log fi}unblock_ip(){ #首先将包个数小于5的ip记录到一个临时文件里,把他们标记为白名单IP iptables -nvL INPUT |sed '1d' |awk '$1<5 {print $8}' > /tmp/good_ip.list n=`wc -l /tmp/good_ip.list |awk '{print $1}'` if [ $n -ne 0 ];then for ip in `cat /tmp/good_ip.list` do iptables -D INPUT -s $ip -j REJECT done echo "`date` 解封的IP有:" >> /tmp/unblock_ip.log cat /tmp/good_ip.list >> /tmp/unblock_ip.log fi #当解封完白名单IP后,将计数器清零,进入下一个技术周期 iptables -Z}#取当前时间的分钟数t=`date +%M`#当分钟数为00或30时(即每隔30分钟),执行解封IP的函数,其他时间只执行封IP的函数if [ $t == "00" ] || [ $t == "30" ];then unblock_ip block_ipelse block_ipfi
增加定时任务:
* * * * * /bin/bash /usr/local/sbin/blockip.sh &>/tmp/blockip.log