目录
实时采集并分析 Nginx 日志, 自动化封禁风险 IP 方案
文章地址:
前言
本文分享了自动化采集, 分析 Nginx 日志并实时封禁风险 IP 的方案及实践.
阅读这篇文章你能收获到:
日志采集方案.
风险 IP 评估的简单方案.
IP 封禁策略及方案.
阅读本文你需要:
熟悉编程.
熟悉常用 Linux 命令.
了解 Docker.
背景
分析 nginx 访问日志时, 看到大量 404 的无效请求, URL 都是随机的一些敏感词. 而且近期这些请求越来越频繁, 手动批量封禁了一些 IP 后, 很快就有新的 IP 进来.
因此萌生了通过自动化分析 Nginx 日志实时封禁 IP 的想法.
需求
序号 | 需求 | 备注 |
---|---|---|
1 | Nginx 日志收集 | 方案有很多, 笔者选择了最适合个人服务器的方案: filebeat + redis |
2 | 日志实时分析 | 实时消费 redis 的日志, 解析出需要的数据进行分析 |
3 | IP 风险评估 | 对 IP 进行风险评估, 多个维度: 访问次数、IP 归属、用途等 |
4 | 实时封禁 | 针对风险 IP 进行不同时长的封禁 |
分析
从日志中简单总结几个特征:
序号 | 特征 | 描述 | 备注 |
---|---|---|---|
1 | 访问频繁 | 每秒数次甚至数十次 | 正常的流量行为也存在突发流量, 但不会持续很久 |
2 | 持续请求 | 持续时间久 | 同上 |
3 | 多数 404 | 请求的 URL 可能大多数都不存在, 且存在敏感词汇如 admin、login、phpMyAdmin、backup 等 | 正常流量行为很少存在这种情况 |
4 | IP 不正常 | 通过 ASN 能看出一些端倪, 一般这类请求的 IP 都不是普通的个人用户. | 查询其用途一般是 COM(商业)、DCH(数据中心 / 网络托管 / 传输)、SES(搜索引擎蜘蛛) 等 |
备注: 这里分析 IP 是通过 https://lite.ip2location.com/ 的免费版数据库, 后面会有详细的描述.
方案
- sequenceDiagram
- participant Nginx
- participant Filebeat
- participant Redis
- participant Monitor
- participant Actuator
- Nginx ->> Filebeat: accessLog(File)
- Filebeat ->> Redis: accessLog(JSON)
- loop Always
- Redis ->> Monitor: accessLog(JSON)
- activate Monitor
- Monitor ->> Monitor: Analysis
- Monitor ->> Monitor: Risk assessment
- Monitor ->> Actuator: Banned
- Monitor ->> Monitor: Storing
- end
- deactivate Monitor
日志采集
- version: '3.5'
- services:
- filebeat:
- image: docker.elastic.co/beats/filebeat:7.4.2
- deploy:
- resources:
- limits:
- memory: 64M
- restart_policy:
- condition: on-failure
- volumes:
- - $PWD/filebeat/filebeat.YAML:/usr/share/filebeat/filebeat.YAML:ro
- - $PWD/filebeat/data:/usr/share/filebeat/data:rw
- - $PWD/nginx/logs:/logs/nginx:ro
- environment:
- TZ: Asia/Shanghai
- depends_on:
- - nginx
- filebeat.inputs:
- - type: log
- enabled: true
- paths:
- - /logs/nginx/access.log
- JSON.keys_under_root: true
- JSON.overwrite_keys: true
- output.Redis:
- hosts: ["redis-server"]
- password: "{your redis password}"
- key: "filebeat:nginx:accesslog"
- db: 0
- timeout: 5
- log_format main_json escape=JSON
- '{'
- '"@timestamp":"$time_iso8601",''"http_host":"$http_host",'
- '"remote_addr":"$remote_addr",''"request_uri":"$request_uri",'
- '"request_method":"$request_method",''"server_protocol":"$server_protocol",'
- '"status":$status,''"request_time":"$request_time",'
- '"body_bytes_sent":$body_bytes_sent,''"http_referer":"$http_referer",'
- '"http_user_agent":"$http_user_agent",''"http_x_forwarded_for":"$http_x_forwarded_for"''}';
- set @a:= inet_aton('172.217.6.78');
- SELECT * FROM ip2location_db11 WHERE ip_from <= @a AND ip_to>= @a LIMIT 1;
- set @a:= inet_aton('172.217.6.78');
- SELECT * FROM ip2location_asn WHERE ip_from <= @a AND ip_to>= @a LIMIT 1;
- set @a:= inet_aton('172.217.6.78');
- SELECT * FROM ip2proxy_px8 WHERE ip_from>= @a AND asn = 15169 ORDER BY ip_from ASC LIMIT 1;
- SELECT * FROM ip2proxy_px8 WHERE ip_from <= @a AND asn = 15169 ORDER BY ip_from DESC LIMIT 1;
- 'use strict';
- const express = require('express');
- const shell = require('shelljs');
- const router = express.Router();
- router.post('/blacklist/:name/:ip', function (req, res, next) {
- let name = req.params.name;
- let ip = req.params.ip;
- let timeout = req.query.timeout;
- let cmd = <code>ipset -exist add ${name} ${ip} timeout ${timeout}</code>;
- console.log(cmd);
- shell.exec(cmd);
- res.send('ok\n');
- });
- module.exports = router;
来源: http://www.tuicool.com/articles/MRNNRjr