Files
obsidian/projects/netbis-sigmatch.md

118 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Netbis Sigmatch — VL 기반 자동 공격 탐지 + CF 차단
updated: 2026-04-24
tags: [netbis, security, ai-defense, wip]
---
## 개요
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 재설계)
### 탐지 트리거 2종만
**A. 집계 기반 공격 모드** (DDoS 검출)
```
현재 5분 총 req > baseline_시간대(UTC hour).p95 × 2.0
OR > baseline_시간대.max × 1.5
→ 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`에 누적
- 시간대(hour_utc)별 p95/max를 최근 7일 롤링 기준으로 실시간 계산
- **공격 판정된 윈도우 샘플은 baseline에 안 들어감** (baseline 오염 방지)
- 매 60 사이클마다 7일 초과 샘플 자동 prune
- 초기 seed는 `baseline_aggregate.py`로 1회 수집, 롤링 12+ 샘플 쌓이면 seed 대체
### 폐기된 이전 설계
- ~~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 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 샘플 부족 시 판정 유예 |
## 파일 구조
```
~/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 규명