개요 — 무엇을 하나
Blocklist & Reputation(/security/blocklist)은 Kitsune ML과 Suricata IDS가 자동으로 차단해 온 위협 대역을 한 화면에 서사화하고, 운영자가 **직접 차단(add) · 해제(release) · 재차단(reblock)**할 수 있는 제어 콘솔입니다.
- 원천 테이블은
legacy_glory커넥션의blacklist_info(약 8~9천 행). 차단 단위는 개별 IP가 아니라 **/24 대역(c_class, 예203.0.113.0/24)**입니다. - 이 테이블은 탐지 수집기(
kts_tx.js·srct_tx.js)와 운영자 UI가 쓰고,sync_black(sync_black.mjs) 데몬이 이를 읽어 각 호스트의 ipset/iptables DROP 규칙으로 집행합니다. 즉 이 화면에서의 add/release는 방화벽 집행의 "제어면"이며, 실제 패킷 차단은 sync_black이 반영합니다. - reason 필드의 소스 태그(
[Kitsune ...]·[Suricata Auto-Block]·[Manual] ...)와 근거 수치(score·port·ja3·hits 등)를 파싱해 "어떤 행동으로 걸렸는지"를 사람이 읽는 라벨로 풀어 줍니다(로케일 독립 파싱).
"차단"은 곧 /24 대역 전체를 막는 조치입니다. 단일 IP를 입력해도 앞 3옥텟만 취해
x.y.z.0/24로 정규화되어 저장됩니다. 오탐 시 면책은 화이트리스트로 처리합니다.
언제 쓰나
- 자동 방어가 지금 무엇을 얼마나 막고 있는지(활성 차단 수·엔진 기여·출신 국가) 한눈에 파악할 때.
- 위협·탐지·IP 조사 팝업에서 확인한 악성 IP를 수동 차단할 때(
?add=딥링크로 프리필됨). - 오탐/정상 대역을 잘못 막았을 때 해제하거나, 재활동이 관측된 해제분을 재차단할 때.
- 차단된 대역의 대표 IP를 AbuseIPDB 평판 조회로 교차 검증할 때.
화면 구성
상단 KPI
summary()가 30초 캐시로 계산합니다(infr:sec:blocklist:summary).
| KPI | 정의 | 계산 |
|---|---|---|
| 활성 차단 | 지금 집행 중인 /24 대역 수 | COUNT(*) WHERE is_use=1 |
| 보호 주소(부제) | 활성 차단이 커버하는 주소 수 | 활성 × 256 (/24 ≈ 256개) |
| 오늘 차단 | 지난 24시간 신규 차단 | is_use=1 AND created_at >= 오늘 00:00 |
| 자동 방어율 | AI·IDS 자동 조치 비율 | (kitsune + suricata) / active × 100 |
| 감시 국가 | 활성 차단 대역의 서로 다른 국가 수 | COUNT(DISTINCT country) WHERE is_use=1 |
| 해제됨 | 현재 해제 상태(재차단 대기) | COUNT(*) WHERE is_use=0 |
자동 방어 엔진 기여
활성 차단을 소스 태그로 분해해 share 바 + 타일로 보여줍니다. 분류는 reason의 LIKE 매칭입니다.
| 엔진 | 매칭 규칙 | 의미 |
|---|---|---|
| Kitsune ML | reason LIKE '%Kitsune%' |
앙상블 오토인코더 이상탐지 |
| Suricata IDS | reason LIKE '%Suricata%' |
스캔·프로토콜 위반 자동차단 |
| 수동 | reason LIKE '%Manual%' 또는 %수동% |
운영자 지정 차단 |
| 기타 | 위 셋에 안 잡힌 나머지 | active − (kitsune+suricata+manual), 최소 0 |
위협 출신지
blockByCountry(12) — 활성 차단 대역을 국가별 상위 12개로 집계(GROUP BY country ORDER BY COUNT DESC)해 국기 이모지 + 랭크 바로 표시합니다. 바를 클릭하면 해당 국가로 목록이 필터됩니다.
최근 방어 활동 피드
blockFeed(16) — 상태 무관 최근 16건(ORDER BY created_at DESC, id DESC)을 4×4 그리드로 보여줍니다. 방금 무엇이 걸렸는지 실시간 감을 줍니다.
필터형 차단 목록
한 페이지 40개 카드(PER_PAGE=40, ORDER BY created_at DESC, id DESC). 각 카드에는 대역·국가·소스 배지·근거칩(behavior + 핵심 수치)·차단 시각·상태와 행 액션 **[평판] · [상세] · [해제]/[재차단]**이 있습니다. 등록된 내부망 대역이면 내부 배지가 붙고 평판 버튼이 숨겨집니다(internal_scope.js).
필터:
- 상태 —
active(기본) ·released·all - 소스 —
kitsune·suricata·manual(빈 값 = 전체) - 국가 — 정확 일치(최대 64자)
- 검색(q) — CIDR 접두 검색만(정규식
^[0-9.]{0,20}$, 예211.→c_class LIKE '211.%')
사용법
근거(reason) 읽는 법
각 카드의 근거칩은 reason 문자열에서 가장 가중치가 높은 룰셋 하나를 골라 라벨 + 대표 수치로 보여줍니다. srct 휴리스틱 카테고리는 다음 가중치 순으로 최상위 1개가 선택됩니다.
| 카테고리 마커 | 가중치 | behavior 키 | 라벨 | 대표 수치(detail) |
|---|---|---|---|---|
[A2:...] |
6 | brute | 관리자 무차별 대입 | hits=N → N hits |
[A:...] |
5 | scanner | 취약 경로 스캔 | hits=N → N hits |
[D:...] |
4 | ja3 | JA3 봇넷 지문 | ja3=N → ja3×N |
[B:...] |
3 | bot_ua | 악성 봇 접속 | hits=N → N hits |
[C:...] |
2 | err_flood | 4xx 오류 폭주 | err_rate=NN% |
[E:...] |
1 | short_scan | TCP 포트 스캔 | port=N 또는 N scan |
Kitsune 소스이거나 reason에 score=가 있으면 카테고리보다 우선해 **ml_anomaly(ML 이상탐지)**로 분류하고 top=(최대 오차 컴포넌트)과 score를 함께 표시합니다. 수동/기타는 manual·auto로 폴백합니다.
reason에서 추가로 추출되는 사실 값: score=, top=, port=, short_scan_sessions=, bytes=. 예시 reason:
[Kitsune v2.2] anomaly top=TLS score=0.83
[Suricata Auto-Block] [A:URL] hits=42 port=443
[Manual] repeated login abuse (uid=5)
수동 차단 추가
- 목록 헤더의 [수동 차단] 버튼 → 추가 모달. (위협/IP 조사에서 넘어온 경우
?add=203.0.113.10으로 IP가 미리 채워집니다.) - IP 또는 CIDR 입력. 단일 IP는
/24로 확장됩니다(203.0.113.10→203.0.113.0/24). - 사유(선택, 최대 160자) 입력 후 [차단].
- 서버 동작:
- 입력을
cclassCidr()로x.y.z.0/24정규화(비 IPv4는invalid_cidr반려). - 완전 IPv4면
ip_info_loop에서 국가를 인리치(없으면 기존 값·Unknown). (server_index=0, c_class)가 이미 있으면is_use=1로 업데이트(재활성 = reactivated), 없으면 신규 insert. reason은"[Manual] <사유> (uid=N)".- 요약 캐시 flush + 목록·요약 즉시 갱신 반환.
- 입력을
차단은 즉시
blacklist_info에 반영되지만, 실제 방화벽 DROP은 각 호스트의sync_black데몬이 다음 동기화 때 ipset/iptables로 집행합니다. 배치가 안 돌면 방화벽에 반영되지 않습니다.
해제 / 재차단
- [해제] —
is_use=0으로 내려 sync_black이 ipset에서 제거하게 합니다(행은 남습니다). 확인 대화상자 후 실행. - [재차단] — 해제분을
is_use=1로 되돌립니다. - 두 작업 모두 대상 행이 없으면
not_found를 반환합니다.
폴링
security-blocklist.js가 30초마다 /security/blocklist/live를 호출해 요약·현재 페이지를 갱신합니다.
데이터 소스
| 항목 | 소스 | 비고 |
|---|---|---|
| 차단 원장 | blacklist_info (legacy_glory) |
id, server_index, c_class, country, reason, is_use, created_at, updated_at · UNIQUE(server_index, c_class) |
| 국가 인리치 | ip_info_loop (legacy_glory) |
add 시 완전 IPv4의 국가 조회 |
| 내부망 판별 | SecurityScope::internalMatchers() |
등록 인스턴스 IP + 운영정책 화이트리스트 → 내부 배지 |
| 방화벽 집행 | sync_black 데몬 |
blacklist_info → ipset/iptables DROP |
| 자동 차단 공급 | kts_tx.js · srct_tx.js |
reason 소스 태그·근거 문자열 기록 |
| 감사 로그 | infr_audit_log |
sec.block_add · sec.block_release · sec.block_readd |
읽기 백본은 App\Repositories\SecurityRepository, 서사·쓰기 오케스트레이션은 App\Services\Security\BlocklistService입니다. 자격증명은 config('database.connections.legacy_glory')만 사용하며 하드코딩하지 않습니다.
권한
- 화면 조회 — Security 역할 영역(사이트맵
min_req=2)에 속해야 접근됩니다. 배포 레벨 기준 staff(5)·admin(10)이 보안 화면을 봅니다(데모(1)는 보안 영역 밖). - 쓰기(add/release/reblock) —
infr_user_level >= 2가 서버에서 강제됩니다(canWrite). 미달이면403 forbidden. 즉 데모(1)는 쓰기 불가, staff·admin은 가능. - 모든 쓰기는
InfrAuditLog에 기록되어 감사 로그에서 추적됩니다(행위자·대상 CIDR·재활성 여부 등 meta 포함).
파괴적 보안 작업이므로 UI가 실행 전 확인(step-up) 대화상자를 띄웁니다. 대량 대역을 실수로 막지 않도록 CIDR을 다시 확인하세요.
문제해결 · FAQ
- 차단했는데 공격이 계속 들어와요. 이 화면은 원장만 갱신합니다. 대상 호스트에
sync_black배치가 돌고 있는지, ipset이 실제로 갱신됐는지 확인하세요. 또한 차단은 /24 단위라 다른 대역에서 오는 공격은 별도 차단이 필요합니다. - [수동 차단]이 403을 반환합니다. 로그인 레벨이 2 미만입니다. staff/admin 계정으로 다시 시도하세요(RBAC 레벨).
- 입력이 "올바른 IP·CIDR이 아닙니다"로 거부됩니다. 형식은
a.b.c/a.b.c.d/a.b.c.d/nn만 허용됩니다. IPv6·호스트명은 지원하지 않습니다. - 국가가 Unknown으로 나옵니다.
ip_info_loop에 해당 IP 인리치가 없거나 CIDR만 입력한 경우입니다. 완전 IPv4로 추가하면 국가가 채워질 수 있습니다. - KPI/목록이 안 바뀌어요. 요약은 30초 캐시입니다. 쓰기 직후에는 flush되지만, 수집기가 채운 변화는 최대 30초 지연될 수 있습니다.
- 정상 대역을 실수로 막았어요. 즉시 **[해제]**하고, 재차단 오탐이 반복되면 화이트리스트에 등록해 srct_tx가 차단 직전 면책하도록 하세요.
관련 항목
- 위협 (Threats) — 여기서 확인한 악성 IP를
?add=로 넘겨 차단 - 화이트리스트 (Whitelist) — 차단 면책(오탐 방지·만료 개념)
- 탐지 & JA3 — Kitsune·srct·JA3 탐지 원리
- 자동 차단 (Auto-block) — 스케줄러 자동 차단 파이프라인
- IP 평판 (AbuseIPDB) — 대표 IP 교차 검증
- 감사 로그 — 차단/해제 이력 추적
