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

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

文章地址: blog.piaoruiqing.com/2019/11/17/…html

前言

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

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

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

閱讀本文你須要:git

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

背景

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

所以萌生了經過自動化分析Nginx日誌實時封禁IP的想法.sql

nginx-404-accesslog

需求

序號 需求 備註
1 Nginx日誌收集 方案有不少, 筆者選擇了最適合我的服務器的方案: filebeat+redis
2 日誌實時分析 實時消費redis的日誌, 解析出須要的數據進行分析
3 IP風險評估 對IP進行風險評估, 多個維度: 訪問次數、IP歸屬、用途等
4 實時封禁 針對風險IP進行不一樣時長的封禁

分析

從日誌中簡單總結幾個特徵:docker

序號 特徵 描述 備註
1 訪問頻繁 每秒數次甚至數十次 正常的流量行爲也存在突發流量, 但不會持續好久
2 持續請求 持續時間久 同上
3 多數404 請求的URL可能大多數都不存在, 且存在敏感詞彙如admin、login、phpMyAdmin、backup等 正常流量行爲不多存在這種狀況
4 IP不正常 經過ASN能看出一些端倪, 通常這類請求的IP都不是普通的我的用戶. 查詢其用途通常是COM(商業)、DCH(數據中心/網絡託管/傳輸)、SES(搜索引擎蜘蛛)等

備註: 這裏分析IP是經過ip2location的免費版數據庫, 後面會有詳細的描述.shell

方案

日誌採集分析處理時序圖

日誌採集

來源: 筆者的網站經過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

[版權聲明]
本文發佈於 樸瑞卿的博客, 容許非商業用途轉載, 但轉載必須保留原做者 樸瑞卿 及連接: blog.piaoruiqing.com. 若有受權方面的協商或合做, 請聯繫郵箱: piaoruiqing@gmail.com.

風險評估

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 proxy_type country_code country_name region_name city_name isp domain usage_type asn as last_seen
    2899904131 2899904131 PUB US United States California Mountain View Google LLC google.com DCH 15169 Google LLC 30
    ip_from ip_to proxy_type country_code country_name region_name city_name isp domain usage_type asn as last_seen
    2899904015 2899904015 PUB US United States California Mountain View Google LLC google.com DCH 15169 Google LLC 30
  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(備份站點), 這樣就算誤殺, 也不會形成用戶沒法訪問的狀況.
  • 道路千萬條, 安全第一條

若是這篇文章對您有幫助,請點個贊吧 ( ̄▽ ̄)"

推薦閱讀

歡迎關注公衆號(代碼如詩)

代碼如詩(poetic_code)
[版權聲明]
本文發佈於 樸瑞卿的博客, 容許非商業用途轉載, 但轉載必須保留原做者 樸瑞卿 及連接: blog.piaoruiqing.com. 若有受權方面的協商或合做, 請聯繫郵箱: piaoruiqing@gmail.com.
相關文章
相關標籤/搜索