我是如何通過Nginx日誌實時封禁風險IP的

實時採集並分析Nginx日誌, 自動化封禁風險IP方案

文章地址: https://blog.piaoruiqing.com/2019/11/17/block-ip-by-analyzing-nginx-logs/

前言

本文分享了自動化採集、分析Nginx日誌並實時封禁風險IP的方案及實踐.

閱讀這篇文章你能收穫到:

  • 日誌採集方案.
  • 風險IP評估的簡單方案.
  • IP封禁策略及方案.

閱讀本文你需要:

  • 熟悉編程.
  • 熟悉常用Linux命令.
  • 瞭解Docker.

背景

分析nginx訪問日誌時, 看到大量404的無效請求, URL都是隨機的一些敏感詞. 而且近期這些請求越來越頻繁, 手動批量封禁了一些IP後, 很快就有新的IP進來.

因此萌生了通過自動化分析Nginx日誌實時封禁IP的想法.

nginx-404-accesslog

需求

序號 需求 備註
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是通過ip2location的免費版數據庫, 後面會有詳細的描述.

方案

NginxFilebeatRedisMonitorActuatoraccessLog(File)accessLog(JSON)accessLog(JSON)AnalysisRisk assessmentBannedStoringloop[ Always ]NginxFilebeatRedisMonitorActuator

日誌採集

來源: 筆者的網站通過docker部署, Nginx作爲唯一入口, 記錄了全部訪問日誌.

採集: 由於資源有限, 筆者選擇了一款輕量的日誌採集工具Filebeat, 收集Nginx日誌並寫入Redis.

風險評估

Monitor服務根據URL、IP、歷史評分等進行風險評估, 計算出最終的危險係數.

IP封禁

Monitor發現危險IP後(危險係數超過閾值), 調用Actuator進行IP封禁, 封禁時長根據危險係數計算得出.

實施

日誌採集

Filebeat的用法很簡單, 筆者通過swarm進行部署, 其部署文件如下(爲防止代碼過長, 此處略去了其他服務):

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.yml:/usr/share/filebeat/filebeat.yml:ro
    - $PWD/filebeat/data:/usr/share/filebeat/data:rw
    - $PWD/nginx/logs:/logs/nginx:ro
    environment:
      TZ: Asia/Shanghai
    depends_on:
    - nginx
  • image: 指定鏡像和版本.
  • deploy.resources.limits.memory: 限制內存.
  • $PWD/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro: filebeat.yml是配置文件, 其中描述了日誌來源和去處. $PWD爲當前目錄, 即執行docker stack deploy的目錄. ro爲只讀權限.
  • $PWD/filebeat/data:/usr/share/filebeat/data:rw: 需要持久化data目錄, 這樣刪除docker重新部署也會記錄上一次讀取日誌的位置.rw爲讀寫權限.
  • $PWD/nginx/logs:/logs/nginx:ro: 將Nginx日誌目錄映射到Filebeat.
  • environment.TZ: 時區

filebeat.yml文件內容如下:

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
  • filebeat.inputs: 定義輸入

  • paths: 日誌路徑

  • json.keys_under_root: 將日誌內容放到json的根節點(如果沒有設置, 整條數據會被放到一個二級節點下). 注: 筆者將nginx日誌配置爲json格式. 參考配置如下:

     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"'
       '}';
    
  • json.overwrite_keys: 覆蓋Filebeat生成的KEY, 此處爲了覆蓋@timestamp字段.

  • output.redis: 定義輸出.

部署成功後查看redis數據:

accesslog-in-redis

風險評估

Monitor服務使用Java編寫, 使用docker部署, 與Actuator服務通過http交互.

風險評估需要綜合多個維度:

序號 維度 策略
1 IP歸屬地 中文網站的用戶羣體一般歸屬地都在中國, 若IP歸屬地爲國外就需要警惕了.
2 用途 通過IP獲取其用途, DCH(數據中心/網絡託管/傳輸)、SES(搜索引擎蜘蛛)等提高危險評分.
3 訪問資源 訪問資源不存在且路徑中含有敏感詞, 如admin、login、phpMyAdmin、backup等, 提高危險評分.
4 訪問頻率及持續時間 頻繁且持久的請求, 考慮提高評分.
5 歷史評分 歷史評分綜合到當前評分中.

獲取IP歸屬地

IP歸屬地獲取比較容易, 有不少數據服務網站提供了免費套餐, 如IpInfo等. 也有免費版IP數據庫可以下載如ip2location等.

筆者使用了ip2location的免費版數據庫:

ip2location

ip_fromip_to是IP段起止, 存儲的格式是十進制, MySQL中可通過inet_aton('your ip')函數將IP轉爲十進制. 如:

set @a:= inet_aton('172.217.6.78');
SELECT * FROM ip2location_db11 WHERE ip_from <= @a AND ip_to >= @a LIMIT 1;
ip_from ip_to country_code country_name region_name city_name latitude longitude zip_code time_zone
2899902464 2899910655 US United States California Mountain View 37.405992 -122.07852 94043 -07:00
  • 數據量很大, 建議帶上LIMIT 1.

獲取AS、ASN及用途

多數網站提供的免費服務中都無法查詢ASN或沒有其用途. ASN數據也有免費的數據庫, 但是依舊沒有其用途及類型等. 此時筆者通過其它的方法曲線救國.

ip2location提供了免費版本的IP2Location™LITE IP-ASNIP2Proxy™LITE數據庫.

IP2Location™LITE IP-ASN: 數據庫提供了確定自治系統和編號(ASN)的參考.

IP2Proxy™LITE: 數據庫包含被用作開放代理的IP地址. 該數據庫包括所有公共IPv4和IPv6地址的代理類型、國家、地區、城市、ISP、域、使用類型、ASN和最新記錄.

IP2Location™LITE IP-ASN中無法查詢到IP的使用類型, IP2Proxy™LITE數據較少中不一定會包含指定的IP. 但可以結合這兩個庫, 大致猜測IP的用途:

  1. 首先, 在IP2Proxy™LITE中查詢出IP的ASN.

    set @a:= inet_aton('172.217.6.78');
    SELECT * FROM ip2location_asn WHERE ip_from <= @a AND ip_to >= @a LIMIT 1;
    
    ip_from ip_to cidr asn as
    2899904000 2899904255 172.217.6.0/24 15169 Google LLC
  2. 結合ASN和IP, 查詢相同ASN最接近指定IP的前後兩條記錄:

    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;
    
    ip_from ip_to region_name isp usage_type asn as
    2899904131 2899904131 California Google LLC DCH 15169 Google LLC
    ip_from ip_to region_name isp usage_type asn as
    2899904015 2899904015 California Google LLC DCH 15169 Google LLC
  3. 計算查詢到的proxy記錄中IP與當前IP的差值的絕對值.

    IP proxy IP abs(IP - proxy IP)
    2899904078 2899904131 53
    2899904078 2899904015 63

    如果絕對值很接近, 那麼就認爲此IP的用途和proxy IP相同. 很接近的定義可以根據情況調整, 如絕對值在65535範圍內.

綜合評分

綜合評分的規則可根據實際場景進行調整

序號 評分項 評分規則(1-10分)
1 IP歸屬地 如: 國內5分, 國外10分, 可根據地區再進行細分
2 用途 如: ISP/MOB計2分, COM計5分, DCH計10分
3 訪問資源 如: 404計5分, 存在敏感詞一律10分
4 訪問頻率及持續時間 根據一段時間內平均訪問次數計算分數
5 歷史評分

綜合上述1-5項, 進行計算, 可以簡單的相加, 也可加權計算.

IP封禁

筆者採用**iptables+ipset**的方式進行IP封禁. Actuator服務使用node編寫, 運行在主機上, docker中的Monitor通過http與其交互. 封禁IP部分代碼如下:

'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 = `ipset -exist add ${name} ${ip} timeout ${timeout}`;
    console.log(cmd);
    shell.exec(cmd);
    res.send('ok\n');
});

module.exports = router;
  • name: 黑名單名稱.
  • timeout: 超時時間, 單位: 秒.

目前, 還是有不少"頭鐵"的IP頻繁掃描筆者的網站, 在發現後幾秒內自動屏蔽掉, 目前效果比較理想.

violation-ticket-list

結語

  • 爬蟲、機器人、漏洞掃描等給網站造成了不必要的開銷甚至帶來風險, 不可忽視. 絕對安全很難做到, 但至少可以做到比別人安全.
  • 封禁是相對暴力的手段, 一定要把握好尺度, 出現誤殺會導致網站流失用戶.
  • 除了封禁外, 也可考慮"禍水東引", 將風險IP 302重定向到gitpage(備份站點), 這樣就算誤殺, 也不會造成用戶無法訪問的情況.
  • 道路千萬條, 安全第一條

推薦閱讀:

歡迎關注公衆號(代碼如詩):
在這裏插入圖片描述

[版權聲明]
本文發佈於樸瑞卿的博客, 允許非商業用途轉載, 但轉載必須保留原作者樸瑞卿 及鏈接:http://blog.piaoruiqing.com. 如有授權方面的協商或合作, 請聯繫郵箱: [email protected].
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章