zoukankan      html  css  js  c++  java
  • 通过监控Nginx日志来实时屏蔽高频恶意访问的IP

    目前在我的VPS上主要通过两种方式来限制ip的访问次数。

    • 通过Nginx的limit_req配置来限制同一ip在一分钟内的访问次数
    • 通过Nginx deny封禁一天内超过指定次数的ip(需要一个监控脚本)

    一、limit_req配置

    Nginx 提供了两个模块:ngx_http_limit_req_modulengx_http_limit_conn_module,前者是限制同一ip在一段时间内的访问总次数,后者是限制同一ip的并发请求次数。

    我的配置主要如下:

    http {
        limit_req_zone $binary_remote_addr zone=onelimit:10m rate=20r/m;
      
        server {
            ...
            location / {
                limit_req zone=onelimit burst=5 nodelay;
                limit_req_log_level warn;
            }
        }
    }
    

    $binary_remote_addr 根据客户端ip作为键值,zone设置唯一标识并设置存储内存大小,每分钟请求不超过20次,否则返回503错误。
    burst=5 表示如果超过频率限制后可缓冲的等待请求数。nodelay表示burst部分不需要等待,nginx会直接处理等待部分的请求。
    limit_req_log_level warn 将匹配到的拦截请求日志等级设置为warn级别。

    看下日志内容:

    2019/03/31 17:57:32 [warn] 9672#9672: *431036 limiting requests, excess: 5.695 by zone "onelimit", client: 183.210.197.101, server: yun.xxx.com, request: "GET /download/ring/b649b722df3c4c86d405d8deb272a59b.mp3 HTTP/1.1", host: "yun.xxx.com", referrer: "http://m.xxx.com/id/61610.html"
    2019/03/31 17:57:39 [warn] 9672#9672: *431038 limiting requests, excess: 5.267 by zone "onelimit", client: 183.210.197.101, server: yun.xxx.com, request: "GET /download/ring/b649b722df3c4c86d405d8deb272a59b.mp3 HTTP/1.1", host: "yun.xxx.com", referrer: "http://m.xxx.com/id/61610.html"
    

    二、Nginx deny配置及监控脚本实现

    limit_req 模块不足的地方在于它只能控制瞬时请求的次数,每秒的请求数 (r/s) 或 每分钟的请求数 (r/m)。这对于恶意访问来源能比较容易的通过控制访问频率来绕过这个检测,这种情况下我主要通过deny配置来直接禁止一天内超过指定次数的ip来源(比如一天访问次数超过100次直接返回403)。设置步骤如下:

    1. 创建blocksip.conf

    在nginx.conf同级目录下创建文件blocksip.conf,在http节点增加以下配置(也可以设置在server节点对单个网站起作用,或location节点只针对特定访问路径的限制)

    include blocksip.conf;
    

    可以在blocksip.conf文件中添加一条测试记录,如服务器ip

    deny 127.0.0.1;
    

    然后重新加载nginx,nginx -s reload,测试下是否生效。

    2. 编写监控脚本,定时更新blocksip.conf文件

    根据nginx请求日志来计算出各ip的top访问次数,根据访问次数将符合条件的ip加入到blocksip.conf文件中,然后重新加载nginx使配置生效即可。

    PHP脚本blocksip.php:

    <?php
    $blockFile = "/etc/nginx/blocksip.conf";
    $logs = ["/var/log/nginx/access-site1.log", "/var/log/nginx/access-site2.log"];
    $blocks = file_get_contents($blockFile);
    $n = 0;
    foreach($logs as $log) {
        $data = shell_exec("cat $log | awk -F ' ' '{print $1}'| sort | uniq -c | sort -n -r | head -n 20");
        $lines = explode("
    ", $data);
    
        foreach($lines as $line) {
            $line = trim($line);
            if (empty($line)) continue;
            $line = explode(" ", $line);
            list($num, $ip) = $line;
    
            if ($num > 100) {
                if (!stristr($blocks, $ip)) {
                    var_dump("[".date("Y-m-d H:i:s")."] New Match $ip");
                    $newBlock = "deny {$ip};" . PHP_EOL;
                    file_put_contents($blockFile, $newBlock, FILE_APPEND);
                    $n++;
                } else {
                    var_dump("Blocked > $ip > $num"); 
                }
            }
        }
    }
    
    if($n > 0) {
        $r = shell_exec("nginx -s reload");
        var_dump("nginx -s reload", $r);
    }
    

    3. 将监控脚本放入crontab定时执行

    每十分钟执行一次

    */10 * * * * /usr/bin/php /etc/nginx/blocksip.php >> /tmp/blocksip.log;
    

    看下拦截日志内容:

    2019/03/31 17:57:26 [error] 9672#9672: *431024 access forbidden by rule, client: 59.80.44.46, server: yun.xxx.com, request: "GET /music/979744fb8eb9055f77f3db2a3f3189a8.mp3 HTTP/1.1", host: "yun.xxx.com"
    2019/03/31 17:57:34 [error] 9672#9672: *431037 access forbidden by rule, client: 59.80.44.46, server: yun.xxx.com, request: "GET /music/979744fb8eb9055f77f3db2a3f3189a8.mp3 HTTP/1.1", host: "yun.xxx.com"
    

    OK, 搞定!

  • 相关阅读:
    CSS边框,背景,边距,溢出
    数字电子技术课程设计之基于触发器的三位二进制同步减法计数器无效态000/110
    集成电路版图与工艺课程设计之用CMOS实现Y=AB+C电路与版图
    金属磁记忆传感器封装
    基于FPGA 的8b10b编解码电路前端电路设计
    Css颜色和文本字体
    Css中的选择器
    Css基本语法及页面引用
    65 插入排序
    63 散列表的查找
  • 原文地址:https://www.cnblogs.com/gouyg/p/10632243.html
Copyright © 2011-2022 走看看