思考了幾種方案,最終考慮使用ip黑名單的方式:nginx
處理方法:算法
1、nginx黑名單方式:shell
一、過濾日誌訪問API接口的IP,統計每10分鐘調用超過100次的IP,直接丟進nginx的訪問黑名單vim
二、具體步驟:瀏覽器
編寫shell腳本:bash
複製代碼
vim /shell/nginx_cutaccesslog.sh
#!/bin/bash
log_path=/xxx/nginx/logs
date=date -d "10 min ago" +%Y%m%d-%H:%M:%S
nginxpid=cat ${log_path}/nginx.pid
cd ${log_path}
#過濾access.log中正常訪問API接口並在10分鐘(下面是日誌切割,再作個定時任務每10分鐘執行一次,就能夠實現了)內訪問量最高的30個IP,取值若是此IP訪問量大於100次,則把此IP放入黑名單
cat access.log | grep sendCheckCode | grep -v 403 | awk '{print $2}'|sort|uniq -c | sort -k1 -n | tail -30 | awk '{if($1>100) print "deny "$2";"}' > ../conf/denyip.conf
#日誌切割,作定時任務,每10分鐘執行一次
mv ${log_path}/access.log ${logpath}/accesslog.bak/access${date}.log
../sbin/nginx -s reload
複製代碼
併發
可本身定義時間間隔和訪問量,也可取消篩選訪問量最高的30個,直接取值每10分鐘訪問接口超過100次的ide
其中:"grep -v 403" 是把已經禁止訪問的IP給過濾掉,只篩選正常訪問的網站
三、修改nginx.confspa
在http模塊加入:
include denyip.conf;
從新加載nginx生效。
四、添加計劃任務:
/10 * /bin/bash /shell/nginx_cutaccesslog.sh > /dev/null 2>&1
五、驗證:
複製代碼
[root@xxx logs]# ll accesslog.bak/
-rw-r--r-- 1 root root 2663901 Jun 5 15:10 access_20180605-15:00:01.log
-rw-r--r-- 1 root root 13696947 Jun 5 15:20 access_20180605-15:10:01.log
-rw-r--r-- 1 root root 13265509 Jun 5 15:30 access_20180605-15:20:01.log
-rw-r--r-- 1 root root 13846297 Jun 5 15:40 access_20180605-15:30:01.log
[root@xxx logs]# cat ../conf/denyip.conf
…………
…………
deny 112.12.137.28;
deny 183.167.237.229;
deny 111.41.43.58;
deny 115.217.117.159;
deny 219.133.100.133;
deny 171.221.254.115;
deny 60.184.131.6;
…………
…………
複製代碼
再查看已經禁用IP的訪問日誌,則會返回403錯誤:
複製代碼
[root@xxx logs]# tail -f access.log | grep "60.184.131.6"
31268622 60.184.131.6 "-" [05/Jun/2018:15:47:34 +0800] 0.000 xxxxxx.com "POST /xxxxxx/sendCheckCode HTTP/1.1" 377 403 168 - - - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
31268622 60.184.131.6 "-" [05/Jun/2018:15:47:35 +0800] 0.000 xxxxxx.com "POST /xxxxxx/sendCheckCode HTTP/1.1" 377 403 168 - - - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
31268622 60.184.131.6 "-" [05/Jun/2018:15:47:35 +0800] 0.000 xxxxxx.com "POST /xxxxxx/sendCheckCode HTTP/1.1" 377 403 168 - - - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
複製代碼
2、限制IP請求數:
處理這種狀況的方法還有一種是限制單 IP 單位時間的請求數,以及單 IP 的併發鏈接數
此方法沒有實際運用,由於感受這種方法會誤殺正常的訪問用戶
寫一下此方法的大概配置,http模塊加入:
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=8r/s;
server {
location /search/ {
limit_req zone=one burst=5;
}
如何估算 limit_req_zone size:
一兆字節區域能夠保持大約1萬6064字節的狀態。
那麼 10M 就能夠存儲 16 萬的 IP 統計信息, 這個對普通應用足夠了,16 萬每秒的 UV,已經超級厲害了。
若是 size 的大小若是設置小了, 例如設置成 1M,那麼當一秒內的請求 IP 數超過 16000 的時候,超出的 IP 對應的用戶看到的均爲 503 Service Temporarily Unavailable 頁面了。參考, 漏桶算法 Leaky Bucket。 同時,rate 的單位用 r/s 很是合適,若是換成按天,按小時計數,10M 的內存確定不夠用。
如何估算 limit_req_zone rate:
首先須要知道的是,普通瀏覽器的同時併發數量。按照 Dropbox 技術博客裏所談到的,目前主流瀏覽器限制 AJAX 對同一個子域名的併發鏈接數是6個。IE 6,IE 7 是兩個。
大多數瀏覽器每一個主機名都有6個併發鏈接的限制。
PS:以上就是感受比較良好的防護惡意IP刷網站的兩種方法,若是你有更好的方法,不妨留言討論一下!
shell 腳本經過nginx日誌封訪問頻率太高的IP
#/bin/bash
#日誌文件
logfile=/usr/local/tengine/logs
last_minutes=1
#開始時間
start_time=date -d"$last_minutes minutes ago" +"%H:%M:%S"
echo $start_time
#結束時間
stop_time=date +"%H:%M:%S"
echo $stop_time
#過濾出單位之間內的日誌並統計最高ip數
tac $logfile/access.log | awk -v st="$start_time" -v et="$stop_time" '{t=substr($4,RSTART+14,21);if(t>=st && t<=et) {print $0}}' \
| awk '{print $1}' | sort | uniq -c | sort -nr > $logfile/log_ip_top10
ip_top=cat $logfile/log_ip_top10 | head -1 | awk '{print $1}'
ip=cat $logfile/log_ip_top10 | awk '{if($1>200)print $2}'
單位時間[1分鐘]內單ip訪問次數超過200次的ip經過ipset封鎖
for line in $ipdoecho $line >> $logfile/black.logipset add blacklist $linedone————————————————