4. 自動封IP和解IP

最愛喝酸奶發表於2019-01-12

對於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_ip
else
    block_ip
fi

增加定時任務:

* * * * * /bin/bash /usr/local/sbin/blockip.sh &>/tmp/blockip.log

相關文章