1.上上個月架構全部遷移上雲以后,總的來說比較穩定,業務量也上來,可愛的壞人也來了,7X24小時不停惡意攻擊我的網站,第一次收到報警是網站流入流量1分鍾以內連續3次超過1000000bps,換算下1M/s秒,平時沒那么大流量的啊,當時剛好在朋友家玩,於趕緊開本本連vpn檢查,發現全是訪問同一個頁面的請求,而且是正常訪問http 200,應該是被惡意攻擊了。
發現問題:
發現問題第一反應,趕緊將請求地址截圖發給開發們看看,問問這個具體是什么?
最后得知是為短信驗證碼接口,據后來統計在被持續攻擊的一個多小時中損失16000多條短信。
解決問題:一期防攻擊策略:
發現問題當然要立馬解決了,當時思路就是統計nginx日志,當單個ip在10秒鍾內訪問 /account/sendPhoneCode次數超過5次,就禁用這個ip,正常用戶不可能有么大的訪問量,於是就有了下面的防攻擊shell腳本。
這個腳本加在定時任務里每分鍾執行一次,半夜0點自動重啟動防火牆,釋放IP,基本上防止了攻擊,大概使用了半個月。
#!/bin/bash #write: lijing QQ 858080796 #date: 20160528 v2.0 #description:攔截非法IP #定義變量 RETVAL=0 Date=$(date '+%Y-%m-%d') Time=$(date '+%Y:%H:%M' -d '-1 minute') MON=$(date|awk -F" " '{print $2}') TODAY=$(date|awk -F" " '{print $3}') Log="/data/logs/nginx/access.log " LINE="70000" #關鍵字 Key01="sendPhoneCode" Status=/tmp/statuS_deny_ip /sbin/service iptables status > $Status #定義函數 #禁止時間函數 secure_deny_time(){ Time01=$(date "+%H:%M:%S" -d " -10 second") Time02=$(date "+%H:%M:%S" -d " -9 second") Time03=$(date "+%H:%M:%S" -d " -8 second") Time04=$(date "+%H:%M:%S" -d " -7 second") Time05=$(date "+%H:%M:%S" -d " -6 second") Time06=$(date "+%H:%M:%S" -d " -5 second") Time07=$(date "+%H:%M:%S" -d " -4 second") Time08=$(date "+%H:%M:%S" -d " -3 second") Time09=$(date "+%H:%M:%S" -d " -2 second") Time10=$(date "+%H:%M:%S" -d " -1 second") echo "$Time01 $Time02 $Time03 $Time04 $Time05 $Time06 $Time07 $Time08 $Time09 $Time10 " } # 禁止關鍵字函數 secure_key(){ tail -n $LINE $LOG |grep "$TODAY\/$MON"|grep -v ^$|grep $TIME|grep $1 |grep $2 |grep $3 |grep $4 |awk -F " " '{print $1}' |sort >> $Deny echo " grep "$TODAY\/$MON" $LOG |grep -v ^$|grep $TIME|grep $1 |grep $2 |grep $3 |grep $4 |awk '{print $1}' |sort" } #執行防火牆攔截函數 secure_deny_ip() { cat $Deny echo ...................... cat $Deny02 for i in $IP;do NUM=$(cat $Deny02|grep $i|awk -F" " '{print $1}') if [ -z $NUM ];then echo " " else if [ $NUM -ge $Dot ];then for y in $i;do grep $y $Status >/dev/null 2>&1 RETVAL=$? [ $RETVAL != 0 ] && echo "/sbin/iptables -I INPUT -s $y -j DROP" [ $RETVAL != 0 ] && /sbin/iptables -I INPUT -s $y -j DROP [ $RETVAL != 0 ] && echo "$(date "+%H:%M:%S") $y " >> /tmp/$Date #[ $RETVAL != 0 ] && /sbin/iptables -I INPUT -s $y -p tcp -j REJECT done fi fi done } NUMBER="1 2 3 4 5 6" for NUMBER in $NUMBER ;do sleep 10s #定義點擊次數 Dot Dot=5 Deny=/tmp/secure_deny_tmp_$NUMBER Deny02=/tmp/secure_deny_$NUMBER #第1次,檢查當前時間以前10s. 如: 0-10秒 echo "第$NUMBER 次,檢查當前時間以前第$NUMBER 個10s.大於 $Dot 次攻擊阻止" echo > $Deny for LOG in `echo $Log` ;do secure_deny_time for TIME in $Time01 $Time02 $Time03 $Time04 $Time05 $Time06 $Time07 $Time08 $Time09 $Time10 ;do secure_key $Key01 done cat $Deny|sort|uniq -c > $Deny02 IP=$(cat $Deny02|awk -F" " '{print $2}') secure_deny_ip done done exit
二期防攻擊策略:
Shell腳本運行的半個月時間里,雖然防止了攻擊,但是公司客服反饋有客戶被誤殺,最嚴重的是公司有次活動,10秒內發5個短信請求很正常啊,誤殺了部分用戶,被防火牆禁止IP不能訪問任何服務。於是得從nginx應用層找方法,不能用老套方法禁IP了,在網上在找幾天的資料解決,幾乎沒有相同的案例,只能自己創造了。
天道酬勤,終於有了兩個思路:
一是nginx結合lua來防攻擊(在網上看得我雲里霧里的,最后不會lua選擇放棄這個方案)。
二是利用ngx_http_referer_module(當時看了2天官網英文資料,http://nginx.org/en/docs/http/ngx_http_referer_module.html,這個頁面的讓我找到方法,尤其是nginx的if 語句)。
對比攻擊日志和正常日志發現,其$http-referer是不同的,如下圖:
正常訪問:
攻擊訪問:
最終解決思路:
1、去掉了原來的 攔截ip策略,不載攔截ip。
2、啟用nignx的location 匹配/account 的$http-referer的過濾,當不是正常$http-referer,直接在再nginx處理。
Nginx配置如下:
location ~ /account(/.*) { if ($http_referer ~ "https://www.xxxxxxxx.net/account/sendPhoneCode") { #如果匹配就直接返回200,返回404,也行啊,自己定。給可愛的攻擊者,不傳給后端web return 200; } #不匹配,傳給后端web proxy_pass http://web_group/account/; }
整個防攻擊到現在沒有出現任何問題,效果杠杠的。后期會增加第三期,主要是我們NB的開發,從程序級解決,如增加各種驗證啊。
http://qiaomiao.blog.51cto.com/484197/1839337