InfraGuard

탐지 룰셋

InfraGuard가 관측·판정하는 44개 탐지 룰셋을 11개 카테고리로 정규화해 개요·해설하고, 카드 클릭으로 그 룰셋에 걸린 최근 이벤트를 되짚는 읽기 전용 카탈로그.

개요 — 무엇을 하나

탐지 룰셋(/security/rulesets)은 InfraGuard가 관측·판정하는 모든 탐지 규칙을 44개 룰셋 / 11개 카테고리로 정규화한 정본(定本) 라이브러리입니다. 이 화면은 세 가지를 한 자리에서 제공합니다.

  1. 개요 — 카테고리별 섹션 안에 룰셋 카드를 배치하고, 선택한 시간 창(1h/6h/24h) 동안 각 룰셋에 실제로 걸린 이벤트 수와 최종 관측 시각을 실측으로 표시합니다.
  2. 해설 — 카드/모달에서 각 룰셋을 3단(무엇을 탐지 · 왜 걸리나 · 최악의 경우)으로 서사화합니다.
  3. 되짚기 — 카드를 클릭하면 그 룰셋으로 실제 걸린 최근 이벤트를 엔진별 테이블로 모달에 펼칩니다.

핵심 설계는 분류 구조와 해설 텍스트의 분리입니다. 구조(카테고리·룰셋 키·엔진별 매칭 규약)는 로케일 독립 정적 SOT인 App\Support\SecurityRulebook이 소유하고(캐시 안전), 해설 텍스트(이름·의미·근거·위험)는 resources/lang/{ko,en}/secrules.php가 소유합니다. 프런트가 key+category로 둘을 병합해 렌더합니다.

이 화면은 완전한 읽기 전용입니다. 룰셋을 켜고 끄거나 편집·삭제하지 않습니다. "이 조직에서 지금 무엇이 관측되고 있으며, 그 의미는 무엇인가"를 이해시키는 참조 카탈로그입니다. 탐지 상수(임계·윈도우)를 실제로 바꾸는 곳은 규칙 임계(Admin ▸ Rules)입니다.

44 룰셋의 원천 = 실 텔레메트리

룰셋은 추상 규칙이 아니라 실제 수집 테이블에 **매칭 규약(match)**으로 결선돼 있습니다. 원천은 전부 legacy_glory 커넥션(수집기 함대가 채우는 레거시 DB)입니다.

엔진 매칭 규약 원천 테이블 룰셋 수
Suricata IDS sig: 시그니처 문자열 소문자 부분일치 배열 suricata_alert_ct 33
웹(nginx) classifyWeb: is_suspicious 요청을 url/ua/status로 우선순위 disjoint 분류 nginx_meta_ct 8
Kitsune ML source=kitsune: 오토인코더 이상 IP kitsune_detail_log 1
휴리스틱(srct) source=srct: 스캔/레이트 휴리스틱 run srct_process_log 1
JA3 지문 source=ja3: 동일 출발지의 JA3 다양성(회전) suricata_tls_ct 1

언제 쓰나

화면 구성

상단 KPI

KPI 라벨 의미
total 룰셋 카탈로그 총 룰셋 수 (항상 44)
active 관측된 룰셋 선택 창에서 이벤트가 1건 이상 발화한 룰셋 수(firing)
events 창 내 이벤트 전 룰셋 이벤트 카운트 합
cats 카테고리 카테고리 수 (11)

내부적으로 엔진별 합(kitsune·suricata 이벤트 합)도 함께 계산돼, Security 퍼널 서사의 "룰셋" 단계 수치와 정합합니다.

컨트롤

카테고리 섹션 + 룰셋 카드

11개 카테고리가 표시 순서대로 섹션을 이루고, 각 섹션 안에 minmax(600) 카드 그리드로 룰셋이 배열됩니다. 카드에는 룰셋 이름·MDI 아이콘·심각도 배지(위급/주의/정보)·창 내 이벤트 수·최근 관측 시각·[자세히]가 표시됩니다. 이벤트가 없으면 "조용함/창 내 관측 없음"으로 표시됩니다.

# 카테고리 키 라벨 엔진 룰셋 수
1 tcp_stream TCP 스트림 무결성 Suricata 10
2 packet_decode 패킷 디코딩 Suricata 4
3 protocol_anomaly 프로토콜 이상 Suricata 5
4 http_anomaly HTTP 규약 Suricata 5
5 tls_anomaly TLS 이상 Suricata 5
6 dns_anomaly DNS 이상 Suricata 1
7 mail_anomaly 메일(SMTP) 이상 Suricata 3
8 web_attack 웹 공격 패턴 nginx 8
9 ml_anomaly ML 이상탐지 Kitsune 1
10 heuristic_scan 휴리스틱 스캔 srct 1
11 tls_fingerprint JA3 지문 JA3 1

사용법

1) 시간 창 선택 → 지형 읽기

먼저 1h/6h/24h 중 관심 창을 고릅니다. active(관측된 룰셋)와 각 카드의 이벤트 수로 지금 무엇이 발화 중인지 파악합니다. 심각도 배지는 암시 심각도임에 유의합니다 — Suricata 엔진 이벤트는 대부분 sev3(정보성)이지만, 그 함의는 다릅니다(잡음/스캔/익스플로잇). 룰셋의 배지는 원본 sev가 아니라 이 함의 톤을 반영합니다.

2) 카드 클릭 → 최근 이벤트 모달

카드를 클릭하면 /security/rulesets/events?key=<룰셋키>&range=<창>을 호출해 모달을 엽니다. 모달 구성:

엔진별 이벤트 테이블 컬럼:

엔진 컬럼
Suricata 시각 · 출발지 · 목적지 · 포트 · proto · 시그니처 · sev
nginx 시각 · 출발지 · host · method · URL(rawurldecode, 180자) · 상태코드
Kitsune 시각 · IP · 이상점수 · 세션수 · 차단여부
srct 시각 · 스캔수 · 차단수 · 메모
JA3 시각 · IP · JA3 다양성 · TLS 접속수 · SNI 다양성

3) 웹 공격 분류 우선순위(disjoint)

웹(nginx) 룰셋 8종은 서로 **배타(disjoint)**입니다. is_suspicious=1 요청 한 건은 카탈로그 정의 순서로 스캔해 첫 매칭 룰셋 하나에만 귀속되고, 어느 패턴에도 안 걸리면 catchall(web_suspicious_other)로 떨어집니다. 즉 같은 요청이 두 웹 룰셋에 이중 집계되지 않습니다.

우선순위 룰셋 키 매칭 단서(url/ua) 심각도
1 web_secret_scan .env .git wp-config id_rsa .aws credentials backup.sql .bak 주의
2 web_path_traversal ../ ..%2f %2e%2e etc/passwd boot.ini proc/self 위급
3 web_sqli union select information_schema sleep( or 1=1 %27or 위급
4 web_xss <script onerror= javascript: document.cookie 주의
5 web_rce_probe /bin/sh exec( system( jndi: ${ phpunit 위급
6 web_admin_brute wp-login xmlrpc.php phpmyadmin /admin/login 주의
7 web_bad_bot UA: sqlmap nikto masscan nuclei python-requests curl/ 주의
8 web_suspicious_other (catchall — 위 어디에도 안 걸린 의심 요청) 정보

웹 분류는 성능을 위해 최근순 표본 6,000건(리포지토리 상한 8,000)으로 집계합니다. 대량 스캔이 있으면 표본 밖 이벤트는 카운트에 반영되지 않을 수 있습니다 — 절대 카운트가 아니라 분포·경향으로 읽어라.

4) Suricata 시그니처 부분일치의 함의

Suricata 룰셋은 시그니처 문자열의 소문자 부분일치로 걸립니다. 예를 들어 stream_invalid_ts는 시그니처에 invalid timestamp가 포함된 모든 이벤트를 합산합니다. 하나의 룰셋이 여러 실제 시그니처를 묶을 수 있고(모달의 "매칭 시그니처" 칩에서 확인), 서로 다른 룰셋의 sig 키워드는 겹치지 않도록 설계됐습니다.

5) 실측 예시(참고)

24시간 창 실측 스냅샷 예: 44 룰셋 중 37개 발화, stream_invalid_ts 10,243건, web_secret_scan 3,304건(대다수 .env류 404), srct_heuristic 126,252건, ja3_rotation 300건(다양성 307/307). 값은 조직·시점에 따라 달라집니다.

데이터 소스

전 원천은 legacy_glory 커넥션(읽기 전용)이며, 하드코딩 자격 없이 config('database.connections.legacy_glory')로만 접속합니다.

룰셋 계열 테이블 리포지토리 메서드(발췌)
Suricata (33) suricata_alert_ct signatureHistogram() · recentAlertsBySignatures() · distinctIpsBySignatures()
웹 (8) nginx_meta_ct (is_suspicious=1) suspiciousRows($since, 6000)
Kitsune ML (1) kitsune_detail_log kitsuneCount() · kitsuneRecentInWindow()
휴리스틱 (1) srct_process_log srctBlockedSum() · srctRunsInWindow()
JA3 (1) suricata_tls_ct topJa3Ips($since, N, excludePrefixes)

성능·캐시

권한

레벨 규약: demo=1 · staff=5 · admin=10. 일부 영역은 infr.level:N 미들웨어로 별도 게이팅됩니다. 자세한 등급 체계는 RBAC 레벨을 참고합니다.

문제해결 · FAQ

모든 카드가 "조용함"으로 표시됩니다

선택 창(기본 24h)에 매칭 이벤트가 없거나, legacy_glory 커넥션이 도달 불가한 경우입니다. 서비스는 원천 오류를 graceful하게 삼켜 빈 카운트(0)로 표시합니다 — 카드가 사라지지는 않습니다. 시간 창을 넓히거나 커넥션을 점검합니다.

웹 룰셋 카운트가 [위협]/[탐지]의 수치와 다릅니다

웹 분류는 최근순 표본 6,000건 기준의 분포 집계다(절대 카운트 아님). 또한 disjoint 분류라 한 요청은 한 룰셋에만 귀속됩니다. 정확한 이벤트 원본은 각 화면의 원천 쿼리를 따릅니다.

특정 시그니처가 어느 룰셋에도 안 잡힙니다

Suricata 매칭은 키워드 부분일치입니다. 카탈로그가 커버하지 않는 신규/커스텀 시그니처는 룰셋 카운트에 합산되지 않습니다. 해설·분류가 필요하면 시그니처 키워드를 SecurityRulebook의 sig 배열에 추가하는 코드 변경이 필요합니다(런타임 설정 아님).

JA3 오펜더가 0인데 TLS 트래픽은 많습니다

JA3 룰셋은 ja3_variety >= 2(지문 회전)인 출발지만 오펜더로 셉니다. 지문 회전이 없으면 정상으로 간주돼 카운트되지 않습니다. 또한 자기망 IP는 제외됩니다.

이벤트 모달에 IP가 내부 배지로 표시됩니다

SecurityScope::internalMatchers()가 판정한 등록 내부망 IP입니다. 우리 서버가 Suricata 방향 라벨상 "출발지"로 찍힐 때의 오인을 막고, 평판 조회 버튼을 숨깁니다. 내부망 정의는 운영 정책(Operations Policy)의 internal_networks에서 관리합니다.

관련 항목

탐지 룰셋 카탈로그
탐지 룰셋 카탈로그