需求說明:
在日常運維工作中,為了防止一些惡意訪問的行為,例如不斷的請求刷流量,通過實時過濾Nginx訪問日誌,將單位時間內訪問次數達到指定閥值的來源ip查詢出來,並通過郵件報警方式及時通知運維人員!
比如針對url為http://192.168.10.202:8888的訪問進行監控,當在1分鐘內訪問次數超過300次數,就郵件報警給運維人員。
1)nginx日誌監控指令碼
[root@Fastdfs_storage_s1 ~]# cat /opt/nginx_log_monit.sh #!/bin/bash #日誌檔案 logfile=/usr/local/nginx/logs/access.log #開始時間 start_time=`date -d"$last_minutes minutes ago" +"%H:%M:%S"` #結束時間 stop_time=`date +"%H:%M:%S"` #過濾出單位之間內的日誌並統計最高ip數 tac $logfile | 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 > /root/log_ip_top10 ip_top=`cat /root/log_ip_top10 | head -1 | awk '{print $1}'` # 單位時間[1分鐘]內單ip訪問次數超過300次,則觸發郵件報警 if [[ $ip_top -gt 300 ]];then /usr/bin/python /opt/send_mail.py & fi
2)python報警指令碼
[root@Fastdfs_storage_s1 ~]# cat /opt/send_mail.py # -*- coding: utf-8 -*- from email import encoders from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from datetime import datetime import os import smtplib def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) # 郵箱定義 smtp_server = 'smtp.kevin.com' smtp_port = 465 from_addr = 'monit@kevin.com' password = os.environ.get('monit@123') to_addr = ['wangshibo@kevin.com'] # 郵件物件 msg = MIMEMultipart() msg['From'] = _format_addr('發件人 <%s>' % from_addr) msg['To'] = _format_addr('收件人 <%s>' % to_addr) msg['Subject'] = Header('Warning:單ip請求次數異常', 'utf-8').encode() # 獲取系統中要傳送的文字內容 with open('/root/log_ip_top10', 'r') as f: line = f.readline().strip() line = line.split(" ") print(line) # 郵件正文是MIMEText: html = '<html><body><h2>一分鐘內單ip請求次數超過閥值</h2>' + \ '<p>ip:%s 請求次數/min:%s</p>' % (line[1],line[0]) + \ '</body></html>' msg.attach(MIMEText(html, 'html', 'utf-8')) server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(from_addr, password) server.sendmail(from_addr, to_addr, msg.as_string()) server.quit()
3)寫個測試指令碼不停curl請求資源觸發報警
[root@Fastdfs_storage_s1 ~]# cat /opt/curl.sh #!/bin/bash #example:curl.sh http://www.kevin.com 100 usage() { echo "usage: `basename $0` url count" } if [ $# -ne 2 ]; then usage exit 1 fi for i in `seq 1 $2`;do http_code=`curl -o /dev/null -s -w %{http_code} $1` echo $1 $http_code done 手動執行測試指令碼 [root@Fastdfs_storage_s1 ~]# /bin/bash /opt/curl.sh http://192.168.10.202:8888 300 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 http://192.168.10.202:8888 200 ...........
4)定時任務,由於上面指令碼是監控一分鐘內的日誌,因此每分鐘執行一次
[root@Fastdfs_storage_s1 ~]# crontab -e * * * * * /bin/bash -x /opt/nginx_log_monit.sh >/dev/null 2>&1
這裡僅僅是實現了郵件告警功能,實際上還可以實現自動遮蔽惡意訪問的ip。
可以通過Nginx deny來實現,也可以通過iptables遮蔽("iptables -I INPUT -s x.x.x.x -j DROP"方式)。