真实案例:
查看 nginx 日志, 发现别有用心的人恶意调用 API 接口刷短信:
- 30966487 115.213.229.38 "-" [05/Jun/2018:14:37:29 +0800] 0.003 xxxxxx.com "POST /xxx/sendCheckCode HTTP/1.1" 401 200 46 xx.xx.xx.xx:0000 0.003 200 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
- 30963985 60.181.111.140 "-" [05/Jun/2018:14:37:29 +0800] 0.004 xxxxxx.com "POST /xxx/sendCheckCode HTTP/1.1" 401 200 46 xx.xx.xx.xx:0000 0.004 200 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
- 30959954 220.190.18.25 "-" [05/Jun/2018:14:37:29 +0800] 0.003 xxxxxx.com "POST /xxx/sendCheckCode HTTP/1.1" 401 200 46 xx.xx.xx.xx:0000 0.003 200 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0" "https://xxxxxx/sendCheckCode"
思考了几种方案, 最终考虑使用 ip 黑名单的方式:
处理方法:
一, nginx 黑名单方式:
1, 过滤日志访问 API 接口的 IP, 统计每 10 分钟调用超过 100 次的 IP, 直接丢进 nginx 的访问黑名单
2, 具体步骤:
编写 shell 脚本:
- 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 ${log_path}/accesslog.bak/access_${date}.log
- ../sbin/nginx -s reload
可自己定义时间间隔和访问量, 也可取消筛选访问量最高的 30 个, 直接取值每 10 分钟访问接口超过 100 次的
其中:"grep -v 403" 是把已经禁止访问的 IP 给过滤掉, 只筛选正常访问的
3, 修改 nginx.conf
在 http 模块加入:
include denyip.conf;
重新加载 nginx 生效.
4, 添加计划任务:
*/10 * * * */bin/bash /shell/nginx_cutaccesslog.sh> /dev/null 2>&1
5, 验证:
- [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"
二, 限制 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 刷网站的两种方法, 如果你有更好的方法, 不妨留言讨论一下!
来源: https://www.cnblogs.com/01-single/p/9140371.html