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
