sigmatch v2 재설계: 집계 기반 공격 모드 + 개별 극단 시그니처 + 롤링 baseline 자동 갱신

This commit is contained in:
kappa
2026-04-24 12:21:46 +09:00
parent 027e3c2a45
commit 2e9244377e

View File

@@ -1,95 +1,114 @@
---
title: Netbis Sigmatch — VL 기반 자동 시그니처 생성 + CF 차단
title: Netbis Sigmatch — VL 기반 자동 공격 탐지 + CF 차단
updated: 2026-04-24
tags: [netbis, security, ai-defense, wip]
---
## 개요
Netbis NPM 로그(VictoriaLogs)를 실시간 분석해 **사람 개입 없이 자동으로 공격 시그니처를 생성**하고 CF IP Access Rules에 차단 반영. LAPI·CrowdSec·LLM 모두 사용 안 함 — 통계/ML 기반.
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, 2026-04-24 재설계)
| 결정 | 값 | 근거 |
|------|-----|------|
| 탐지 주기 | 1분 (슬라이딩 윈도우 5분) | 5분 내 방어 개시 목표 |
| 분석 대상 | 5분 요청 100+ IP만 | 통계적 유의성 확보, 노이즈 제거 |
| LLM 사용 | **없음** | 이전 `ddos-detect` 실패 원인(매 요청 LLM 동기 호출) 교훈 |
| LAPI 경유 | **없음** | Netbis는 로그 파이프라인이 독립, LAPI 중간 레이어 불필요 |
| 차단 저장소 | CF IP Access Rules 직접 | 한도 50k (vs Custom List 10k) |
| Feature | 13종 + 메타 (경로 문자열·UA 문자열 비의존) | 공격 path·UA가 매번 바뀌어도 시그니처 재사용 가능 |
### 탐지 트리거 2종만
## Feature 확정
**A. 집계 기반 공격 모드** (DDoS 검출)
```
현재 5분 총 req > baseline_시간대(UTC hour).p95 × 2.0
OR > baseline_시간대.max × 1.5
→ attack mode ON → top N contributor IP challenge
```
5분 윈도우, 요청 100+ IP.
**B. 개별 극단 (항상 동작)**
```
Scanner-shape: uniq_paths/reqs ≥ 0.8 AND path_entropy ≥ 7 AND reqs ≥ 300
(수백 경로를 각 1회씩 = 취약점 스캐너)
Raw extreme: reqs ≥ 1500 / 5min
(폴링 유저 상한의 약 7배)
```
| 카테고리 | Feature |
|---------|---------|
| 볼륨 | reqs, rate_per_min |
| 경로 shape | path_entropy, top_path_ratio, uniq_paths |
| UA | ua_count |
| 응답 | status_2xx_ratio, status_4xx_ratio |
| 간격 | iri_mean, iri_p50, iri_p90, iri_cv |
| 행동 | static_ratio, ref_count, ref_top_ratio, active_sec, has_post |
| 메타 | is_reserved (240/4 플래그) |
### 롤링 baseline (자동 갱신)
### 제거된 후보
- 매 사이클 현재 윈도우 샘플을 `baseline_samples`에 누적
- 시간대(hour_utc)별 p95/max를 최근 7일 롤링 기준으로 실시간 계산
- **공격 판정된 윈도우 샘플은 baseline에 안 들어감** (baseline 오염 방지)
- 매 60 사이클마다 7일 초과 샘플 자동 prune
- 초기 seed는 `baseline_aggregate.py`로 1회 수집, 롤링 12+ 샘플 쌓이면 seed 대체
- `top_path`·`top_ua` 문자열 — 공격자가 매번 바꿈. 시그니처가 종속되면 재생성 부담
- `ref_none_ratio`, `ref_external_ratio` — 봇도 referer 세팅, 실측 전부 0
- UA 문자열 기반 봇 분류 — 정교한 봇은 정상 Chrome/Safari UA 사용
### 폐기된 이전 설계
- ~~IsolationForest + DBSCAN per-IP anomaly~~ → 정상 폴링 유저를 outlier로 잡아 오탐 위험
- ~~Persistence 단독 트리거~~ → 페이지 오래 열어둔 유저 6 사이클 지속 시 오탐
- ~~사전 정의 hard rule (R1~R6)~~ → 공격 패턴 종속, 자동 시그니처 생성 취지 어긋남
## 오탐 방지 특성
| 상황 | 동작 |
|------|------|
| 평상시 정상 트래픽 | 액션 0 (heavy user·폴링 유저 다 통과) |
| 평상시 섞인 취약점 스캐너 | 개별 극단 트리거 (확정 공격) |
| DDoS·대규모 공격 | attack mode 발동 → top contributor 일괄 challenge |
| 가짜 공격 (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+ 사이클 연속 공격 시
## 개발 단계
- [x] Phase 1: feature 추출 파이프라인 (`fetch_features.py`)
- [x] Phase 2: 24h baseline 수집기 (retrospective, `collect_baseline.py`)
- [x] Phase 3: IsolationForest 기반 anomaly detection (loop.py 내)
- [x] Phase 4: DBSCAN 클러스터링 + 단발 봇 persistence 탐지 (loop.py 내)
- [x] Phase 5: state DB (IP별 persistence/action 이력, `state.py`)
- [ ] **Phase 5b: 장시간 관찰 (현재 진행)** — 수 시간~1일 dry-run, 실제 공격 도달 시 거동 확인
- [ ] Phase 6: CF IP Access Rules 호출 (managed_challenge → block 승급)
- [ ] Phase 7: jp1 Incus 배포 (systemd timer)
- [x] Phase 1: feature 추출 (`fetch_features.py`)
- [x] Phase 2: 24h retrospective baseline (`collect_baseline.py`)
- [x] Phase 3-5: (폐기) IsolationForest+DBSCAN+persistence 기반
- [x] **Phase 6 (v2): 집계 기반 공격 모드 + 개별 극단 시그니처** ← 현재
- [x] **Phase 7: 롤링 baseline 자동 갱신** ← 현재
- [ ] Phase 8: 장시간 관찰 (dry-run) — 진행 중 (백그라운드 `loop.py`)
- [ ] Phase 9: CF IP Access Rules 호출 (managed_challenge → block)
- [ ] Phase 10: 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 중 이 이상인 것만 |
| `scanner_uniq_ratio` | 0.8 | uniq_paths/reqs 임계 |
| `scanner_min_entropy` | 7.0 | path entropy 임계 |
| `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 샘플 부족 시 판정 유예 |
**2트랙 탐지**:
## 파일 구조
1. **클러스터 기반 (캠페인 공격)**
- IsolationForest로 outlier 추출
- DBSCAN으로 outlier 간 유사 패턴 클러스터
- 클러스터 강도(크기·rate·성공률) 평가 → challenge
- 연속 5+ 사이클 지속 시 block 승급
2. **단발 지속 (개별 봇)**
- 클러스터 미형성 noise outlier 중
- 3+ 사이클 연속 + anomaly_score 하위 50% 이내
- → challenge, 5+ 사이클 지속 → block
**조치 레벨**:
- challenge: Cloudflare managed_challenge (CAPTCHA), TTL 30분 — 정상 유저는 한 번 풀고 통과
- block: TTL 24시간 — challenge 통과 후에도 공격 지속 시만
**사람이 조정하는 건 파라미터만** (코드에 공격 지식 없음):
- `min_cluster_ips` (클러스터 최소 IP 수)
- `min_avg_rate`, `min_success` (강도 임계)
- `persistence_for_challenge`, `persistence_for_block` (승급 기준)
- DBSCAN eps, min_samples
- TTL
## 관찰된 공격 유형 (2026-04-24 실측)
**유형 A — 리소스 크롤러**: static_ratio > 0.5, iri_p90 < 0.1, uniq_paths > 50, 짧은 active
**유형 B — API/HTML 봇**: static_ratio < 0.05, iri_p90 5~8s, path_entropy < 5, top_path_ratio 0.2~0.3, active 200s+
**루프 봇**: ref_top_ratio >= 0.9 + reqs >= 100 (단독 ban 기준 후보)
```
~/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/ — 사이클 로그
```
## 연관 정본