7.4 KiB
7.4 KiB
title, updated, tags
| title | updated | tags | ||||
|---|---|---|---|---|---|---|
| Netbis Sigmatch — VL 기반 자동 공격 탐지 + CF 차단 | 2026-04-24 |
|
개요
Netbis NPM 로그(VictoriaLogs)를 실시간 분석해 사람 개입 없이 공격을 자동 탐지하고 CF IP Access Rules에 challenge/block 반영. LAPI·CrowdSec·LLM·사전 정의 룰 모두 사용 안 함.
- 저장소: https://gitea.inouter.com/kaffa/netbis-sigmatch
- 로컬 개발:
~/netbis-sigmatch/(Mac) - 배포 예정: jp1 Incus
ai-sigmatch컨테이너 (systemd timer 1분) - 책임자: kappa 직접 개발 (Heimdall 위임 X, 개발 단계)
핵심 설계 (v2.1, 2026-04-24 CUSUM + global entropy 추가)
탐지 트리거 (OR 조건, 하나라도 충족 시 attack mode ON)
A1. Static threshold (급격한 볼륨 이상)
현재 5분 총 req > baseline_시간대(UTC hour).p95 × 2.0
OR > baseline_시간대.max × 1.5
A2. CUSUM Page-Hinkley (점진적 ramp-up 공격)
g_t = max(0, g_{t-1} + (x_t - μ_hour - δ)) , δ = μ × 0.3
g_t > μ × 2.0 → trigger → reset g=0
- μ는 시간대별 롤링 mean. static threshold를 못 넘게 살살 올리는 low-rate DDoS 커버
- 전역 g_t 1개 유지 (hour 경계 reset 문제 회피)
A3. Global src IP entropy drop (소수 IP 집중 공격)
현재 5분 트래픽의 Shannon(Counter(client_ip)) < baseline_entropy_p10(시간대별)
- entropy 계산은
min_entropy_baseline_samples=20확보 후부터 uniq_ips < entropy_min_uniq_ips=30이면 판정 스킵 (트래픽 자체가 너무 적을 때)
→ attack mode ON: top N contributor IP 일괄 challenge
B. 개별 극단 (항상 동작)
Scanner-shape: uniq_paths/reqs ≥ 0.8 AND path_entropy ≥ 7 AND reqs ≥ 300
(수백 경로를 각 1회씩 = 취약점 스캐너)
Raw extreme: reqs ≥ 1500 / 5min
(폴링 유저 상한의 약 7배)
롤링 baseline (자동 갱신)
- 매 사이클 현재 윈도우 샘플을
baseline_samples에 누적 (total_reqs + src_ip_entropy + uniq_ips) - 시간대(hour_utc)별 mean/p95/max/entropy_p10/entropy_p50을 최근 7일 롤링 기준으로 실시간 계산
- 공격 판정된 윈도우 샘플은 baseline에 안 들어감 (baseline 오염 방지)
- 매 60 사이클마다 7일 초과 샘플 자동 prune
- 초기 seed는
baseline_aggregate.py로 1회 수집, 롤링 12+ 샘플 쌓이면 seed 대체
오탐 방지 특성
| 상황 | 동작 |
|---|---|
| 평상시 정상 트래픽 | 액션 0 (heavy user·폴링 유저 다 통과) |
| 평상시 섞인 취약점 스캐너 | 개별 극단 트리거 (확정 공격) |
| DDoS·대규모 공격 (급격) | static threshold (p95×2.0 / max×1.5) 발동 |
| Low-rate / 점진 ramp-up DDoS | CUSUM Page-Hinkley 누적으로 발동 |
| 소수 IP 집중 공격 (같은 볼륨) | global src IP entropy drop으로 발동 |
| 가짜 공격 (baseline 경계선) | samples ≥ 10 확보 후에만 판정 (초기 1~2일은 판정 유예) |
사람이 쓴 공격 지식 없음:
- 특정 경로·ASN·UA 리스트 없음
- scanner-shape는 행동 통계 (uniq_paths/reqs 비율, entropy)
- attack mode는 트래픽 볼륨 이상 — 자기 과거와의 편차만 봄
조치 레벨
- challenge (Cloudflare managed_challenge, CAPTCHA, TTL 30분): 정상 유저는 한 번 풀고 통과
- block (TTL 24시간): challenge 통과 후에도 같은 IP가 5+ 사이클 연속 공격 시
개발 단계
- Phase 1: feature 추출 (
fetch_features.py) - Phase 2: 24h retrospective baseline (
collect_baseline.py) - Phase 3-5: (폐기) IsolationForest+DBSCAN+persistence 기반
- Phase 6 (v2): 집계 기반 공격 모드 + 개별 극단 시그니처
- Phase 7: 롤링 baseline 자동 갱신
- Phase 8 (v2.1): CUSUM Page-Hinkley + global src IP entropy drop ← 현재
- Phase 9: 장시간 관찰 (dry-run) — 진행 중 (백그라운드
loop.py). entropy baseline 20+ 샘플 쌓이려면 약 20시간 - Phase 10: CF IP Access Rules 호출 (managed_challenge → block)
- Phase 11: jp1 Incus 배포 (systemd timer)
파라미터 (사람 조정 가능)
| 파라미터 | 기본값 | 의미 |
|---|---|---|
attack_p95_multiplier |
2.0 | 현재 req가 시간대 p95의 몇 배면 attack mode |
attack_max_multiplier |
1.5 | 또는 max의 몇 배면 |
attack_top_n |
20 | attack 시 challenge할 상위 IP 수 |
attack_contributor_min_reqs |
200 | top IP 중 이 이상인 것만 |
cusum_drift_pct |
0.3 | CUSUM 허용 드리프트 δ = μ × pct |
cusum_threshold_mult |
2.0 | CUSUM 트리거 h = μ × mult |
min_entropy_baseline_samples |
20 | entropy baseline 샘플 부족 시 판정 스킵 |
entropy_min_uniq_ips |
30 | uniq IP 부족 시 entropy 판정 스킵 |
scanner_uniq_ratio |
0.8 | uniq_paths/reqs 임계 |
scanner_min_entropy |
7.0 | path entropy 임계 (per-IP) |
scanner_min_reqs |
300 | 스캐너 최소 요청 수 |
extreme_reqs |
1500 | 단일 IP 극단 rate 임계 |
persistence_for_block |
5 | challenge → block 승급 사이클 |
challenge_ttl_sec |
1800 | 30분 |
block_ttl_sec |
86400 | 24시간 |
baseline_rolling_days |
7 | 롤링 윈도우 |
min_baseline_samples |
10 | baseline 샘플 부족 시 판정 유예 |
검증 결과 (simulate.py)
- 평상시 24h 데이터: static threshold 0회 발동, CUSUM hour별 μ 적용 시 0회 오탐
- 마지막 5개 윈도우에 1.5x→3.5x 점진 ramp 주입: CUSUM 3회 발동 (idx 198/199/200 연속)
- CUSUM 유닛 테스트: 평상시 g=0 유지, ramp-up 시 g 누적 → h 초과 시 trigger + reset 확인
폐기된 이전 설계
IsolationForest + DBSCAN per-IP anomaly→ 정상 폴링 유저를 outlier로 잡아 오탐 위험Persistence 단독 트리거→ 페이지 오래 열어둔 유저 6 사이클 지속 시 오탐사전 정의 hard rule (R1~R6)→ 공격 패턴 종속, 자동 시그니처 생성 취지 어긋남
폐기 후보 (검토 후 불채택)
- Prophet / LSTM / Bi-LSTM — 라벨 없음, 학습·추론 무거움, jp1 작은 컨테이너 오버킬
- CatBoost / Random Forest 지도학습 — 라벨 필요
- per-IP Isolation Forest / OC-SVM — 정상 폴링 유저 오탐 (이미 폐기 이유 동일)
향후 데이터 2주+ 쌓이면 검토 예정:
- Holt-Winters — level+trend+seasonality. 현재 static p95×mult 대체 가능
- Aggregate-window Isolation Forest — per-IP 아닌 "윈도우 다변량 feature" anomaly
파일 구조
~/netbis-sigmatch/
├── fetch_features.py — feature 추출 (단발 조회)
├── collect_baseline.py — retrospective seed baseline 수집
├── baseline_aggregate.py — 시간대별 seed 통계 수집 (1회성)
├── inspect_baseline.py — baseline DB 탐색
├── state.py — state DB (ip_state, baseline_samples 등)
├── loop.py — 메인 실시간 루프
├── simulate.py — 과거 데이터로 로직 검증
├── baseline.db — seed snapshot 24h
├── state.db — 운영 상태 + 롤링 baseline
└── logs/ — 사이클 로그
연관 정본
- ../services/netbis — NPM → VL 파이프라인
- ../infra/security/cloudflare#Pseudo IPv4 (Class E 240/4) — 240/4 대역 해석
- ../history/2026-04-24-cf-pseudo-ipv4-discovery — CF Pseudo IPv4 규명