본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 27. · 2 Views
보안 운영 자동화 완벽 가이드
종합 보안 스캐너부터 SIEM 룰 작성, 위협 헌팅, 인시던트 대응 자동화까지 실무 보안 운영의 모든 것을 다룹니다. 초급 개발자도 이해할 수 있도록 스토리텔링 형식으로 쉽게 설명합니다.
목차
1. 종합 보안 스캐너 개발
어느 날 김개발 씨는 회사의 서버들이 안전한지 확인해달라는 요청을 받았습니다. 서버가 10대가 넘는데, 하나하나 수동으로 점검하려니 막막했습니다.
"이걸 자동화할 수 있는 방법이 없을까요?" 선배 박시니어 씨가 미소를 지으며 말했습니다. "종합 보안 스캐너를 만들어보는 건 어때요?"
종합 보안 스캐너란 여러 보안 점검 기능을 하나로 통합한 자동화 도구입니다. 마치 건강검진센터에서 여러 검사를 한 번에 받는 것처럼, 서버의 포트 상태, 서비스 버전, 알려진 취약점을 일괄적으로 점검합니다.
이를 통해 수작업으로 몇 시간 걸리던 작업을 몇 분 만에 완료할 수 있습니다.
다음 코드를 살펴봅시다.
import socket
import concurrent.futures
from dataclasses import dataclass
from typing import List, Dict
@dataclass
class ScanResult:
host: str
open_ports: List[int]
vulnerabilities: List[str]
class SecurityScanner:
def __init__(self, targets: List[str]):
self.targets = targets
self.results: Dict[str, ScanResult] = {}
def scan_port(self, host: str, port: int) -> bool:
# 소켓으로 포트 연결 시도
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex((host, port))
sock.close()
return result == 0
except:
return False
def run_scan(self, host: str) -> ScanResult:
# 주요 포트 스캔 수행
common_ports = [22, 80, 443, 3306, 5432, 6379, 8080]
open_ports = [p for p in common_ports if self.scan_port(host, p)]
return ScanResult(host=host, open_ports=open_ports, vulnerabilities=[])
김개발 씨는 입사 6개월 차 주니어 개발자입니다. 최근 회사에서 보안 강화 프로젝트가 시작되면서, 운영 중인 모든 서버의 보안 상태를 점검해야 하는 임무를 맡게 되었습니다.
처음에는 각 서버에 SSH로 접속해서 하나씩 확인하려 했지만, 서버가 15대나 되다 보니 엄두가 나지 않았습니다. "선배님, 이걸 일일이 손으로 확인하려면 며칠은 걸릴 것 같아요." 김개발 씨가 한숨을 쉬자 박시니어 씨가 의자를 끌고 다가왔습니다.
"우리가 개발자인데, 왜 손으로 하려고 해요? 자동화 스크립트를 만들어봐요." 그렇다면 종합 보안 스캐너란 정확히 무엇일까요?
쉽게 비유하자면, 종합 보안 스캐너는 마치 종합 건강검진 센터와 같습니다. 병원에 가면 혈액 검사, 엑스레이, 초음파 등 여러 검사를 한 곳에서 받을 수 있잖아요.
보안 스캐너도 마찬가지입니다. 포트 스캔, 서비스 버전 확인, 취약점 분석 등 여러 보안 점검을 하나의 도구에서 수행합니다.
종합 보안 스캐너가 없던 시절에는 어땠을까요? 개발자들은 nmap으로 포트를 확인하고, 별도의 도구로 취약점을 스캔하고, 또 다른 스크립트로 결과를 정리해야 했습니다.
도구마다 출력 형식이 달라서 결과를 통합하기도 어려웠습니다. 더 큰 문제는 사람이 직접 해야 하다 보니 휴먼 에러가 발생한다는 것이었습니다.
바로 이런 문제를 해결하기 위해 종합 보안 스캐너를 개발합니다. 하나의 스크립트로 모든 점검을 수행하고, 결과를 일관된 형식으로 출력합니다.
무엇보다 재현 가능한 점검이 가능해집니다. 같은 스캐너를 돌리면 언제나 같은 방식으로 점검하니까요.
위의 코드를 살펴보겠습니다. 먼저 ScanResult 데이터 클래스를 정의합니다.
이 클래스는 스캔 결과를 담는 그릇 역할을 합니다. 어떤 호스트에서 어떤 포트가 열려 있고, 어떤 취약점이 발견되었는지 깔끔하게 정리할 수 있습니다.
SecurityScanner 클래스의 scan_port 메서드가 핵심입니다. 소켓을 생성해서 특정 포트에 연결을 시도합니다.
연결이 성공하면 해당 포트가 열려 있다는 의미입니다. 타임아웃을 1초로 설정해서 응답이 없는 포트에서 오래 기다리지 않도록 했습니다.
실제 현업에서는 이 기본 구조 위에 다양한 기능을 추가합니다. 예를 들어 멀티스레딩으로 여러 호스트를 동시에 스캔하거나, 발견된 서비스의 버전을 확인하는 배너 그래빙 기능을 넣기도 합니다.
스캔 결과를 JSON이나 HTML 리포트로 출력하는 기능도 유용합니다. 하지만 주의할 점도 있습니다.
무분별한 포트 스캔은 법적 문제를 일으킬 수 있습니다. 반드시 자신이 관리하는 시스템이나 명시적으로 허가받은 대상에만 스캔을 수행해야 합니다.
또한 스캔 속도가 너무 빠르면 네트워크 장비에서 차단될 수 있으니 적절한 지연을 두는 것이 좋습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 도움을 받아 보안 스캐너를 완성한 김개발 씨는 15대 서버의 보안 점검을 30분 만에 끝냈습니다. "이제 매주 자동으로 돌려서 변화를 추적할 수도 있겠네요!" 보안 자동화의 첫걸음을 뗀 순간이었습니다.
실전 팁
💡 - concurrent.futures를 활용하면 여러 호스트를 병렬로 스캔하여 속도를 크게 높일 수 있습니다
- 스캔 결과는 반드시 로그로 남기고, 이전 결과와 비교하여 변화를 추적하세요
- 프로덕션 환경에서는 스캔 시간을 업무 외 시간으로 예약하는 것이 좋습니다
2. 포트 스캔 및 취약점 스캔 통합
김개발 씨가 만든 기본 스캐너는 잘 동작했지만, 한 가지 아쉬운 점이 있었습니다. "포트가 열려 있다는 건 알겠는데, 그래서 이게 위험한 건가요?" 보안팀 이보안 씨가 물었습니다.
단순히 열린 포트를 나열하는 것만으로는 부족했습니다. 어떤 서비스가 돌아가고 있고, 알려진 취약점이 있는지까지 알아야 했습니다.
취약점 스캔 통합이란 포트 스캔 결과에 보안 위험도 정보를 결합하는 것입니다. 마치 의사가 검사 결과를 보고 "이 수치가 정상 범위를 벗어났으니 주의가 필요합니다"라고 해석해주는 것과 같습니다.
열린 포트에서 실행 중인 서비스와 버전을 파악하고, 알려진 취약점 데이터베이스와 대조하여 실제 위험을 평가합니다.
다음 코드를 살펴봅시다.
import socket
import re
from typing import Optional, Dict, List
# 알려진 취약점 데이터베이스 (실제로는 NVD API 연동)
VULN_DATABASE = {
"OpenSSH_7.4": ["CVE-2017-15906", "CVE-2018-15473"],
"Apache/2.4.6": ["CVE-2017-15710", "CVE-2018-1312"],
"nginx/1.12": ["CVE-2017-7529"],
}
class VulnerabilityScanner:
def grab_banner(self, host: str, port: int) -> Optional[str]:
# 서비스 배너 수집으로 버전 정보 획득
try:
sock = socket.socket()
sock.settimeout(2)
sock.connect((host, port))
sock.send(b"HEAD / HTTP/1.0\r\n\r\n")
banner = sock.recv(1024).decode(errors='ignore')
sock.close()
return banner
except:
return None
def check_vulnerabilities(self, banner: str) -> List[Dict]:
# 배너에서 서비스 버전 추출 후 취약점 매칭
vulnerabilities = []
for service, cves in VULN_DATABASE.items():
if service in banner:
for cve in cves:
vulnerabilities.append({
"service": service,
"cve": cve,
"severity": "HIGH"
})
return vulnerabilities
김개발 씨는 스캐너 결과를 보안팀에 전달했습니다. "3번 서버에 22번, 80번, 3306번 포트가 열려 있습니다." 이보안 씨가 고개를 갸웃했습니다.
"음, 그래서 이게 문제인 건가요? SSH가 열려 있는 건 당연하고, 웹 서버도 필요하잖아요.
중요한 건 거기서 뭐가 돌아가고 있느냐예요." 그제야 김개발 씨는 깨달았습니다. 포트가 열려 있다는 사실 자체가 문제가 아니라, 그 포트에서 취약한 버전의 서비스가 돌아가고 있을 때가 진짜 위험한 것입니다.
배너 그래빙이라는 기술이 있습니다. 쉽게 말하면 서비스에게 "너 누구니?"라고 물어보는 것입니다.
대부분의 서비스는 친절하게 자신의 이름과 버전을 알려줍니다. "저는 Apache 2.4.6이에요"라고 말이죠.
이 정보만 있으면 알려진 취약점 목록과 대조할 수 있습니다. 코드를 살펴보면, grab_banner 메서드가 이 역할을 합니다.
소켓으로 연결한 뒤 간단한 HTTP 요청을 보내면, 서버가 응답하면서 자신의 정보를 노출합니다. 예를 들어 "Server: Apache/2.4.6" 같은 헤더가 돌아옵니다.
VULN_DATABASE는 실제로는 **NVD(National Vulnerability Database)**나 CVE 데이터베이스 API와 연동합니다. 여기서는 간단히 딕셔너리로 표현했지만, 실무에서는 수십만 개의 취약점 정보가 담긴 데이터베이스를 조회합니다.
이 두 가지를 결합하면 강력한 취약점 스캐너가 됩니다. 포트 스캔으로 열린 포트를 찾고, 배너 그래빙으로 서비스 버전을 확인하고, CVE 데이터베이스와 대조하여 알려진 취약점이 있는지 확인합니다.
이 과정이 자동으로 진행되니 수백 대의 서버도 빠르게 점검할 수 있습니다. 주의할 점은 모든 서비스가 배너를 노출하지는 않는다는 것입니다.
보안이 강화된 환경에서는 배너를 숨기거나 가짜 정보를 보여주기도 합니다. 따라서 배너 정보만으로 100% 정확한 판단을 내리기는 어렵습니다.
중요한 시스템은 추가적인 수동 검증이 필요합니다. 이보안 씨가 새로운 스캐너 결과를 받아보았습니다.
"오, 이제 보이네요. 3번 서버의 Apache가 2.4.6 버전이고, CVE-2017-15710 취약점이 있군요.
이건 빨리 패치해야겠어요." 김개발 씨의 스캐너가 드디어 실질적인 가치를 만들어내기 시작했습니다.
실전 팁
💡 - NVD API나 vulners.com API를 연동하면 최신 취약점 정보를 실시간으로 확인할 수 있습니다
- 배너 그래빙 외에도 nmap의 서비스 탐지 기능(-sV)을 subprocess로 호출하면 더 정확한 결과를 얻을 수 있습니다
- CVSS 점수를 함께 표시하면 취약점의 심각도를 한눈에 파악할 수 있습니다
3. SIEM 룰 작성 및 튜닝
보안팀에서 새로운 요청이 들어왔습니다. "스캐너로 취약점은 찾았는데, 실시간으로 공격을 탐지하려면 어떻게 해야 하죠?" 이보안 씨가 SIEM이라는 시스템을 소개해주었습니다.
하지만 SIEM에 들어가는 탐지 룰을 작성하는 건 또 다른 영역의 일이었습니다. 김개발 씨는 새로운 도전 앞에 섰습니다.
**SIEM(Security Information and Event Management)**은 보안 이벤트를 수집하고 분석하는 중앙 시스템입니다. 마치 CCTV 관제센터처럼 여러 곳에서 들어오는 로그를 한곳에서 모니터링합니다.
SIEM 룰은 "이런 패턴이 보이면 경보를 울려라"라는 규칙입니다. 좋은 룰은 진짜 위협은 잡아내고, 오탐은 최소화해야 합니다.
다음 코드를 살펴봅시다.
from dataclasses import dataclass
from typing import List, Dict, Any
from datetime import datetime, timedelta
@dataclass
class SIEMRule:
name: str
description: str
query: str
threshold: int
time_window: timedelta
severity: str
class SIEMRuleEngine:
def __init__(self):
self.rules: List[SIEMRule] = []
self.alerts: List[Dict] = []
def add_rule(self, rule: SIEMRule):
# 탐지 룰 등록
self.rules.append(rule)
def evaluate(self, events: List[Dict[str, Any]]) -> List[Dict]:
# 이벤트 스트림에서 룰 매칭 수행
for rule in self.rules:
matching = [e for e in events if self._matches(e, rule.query)]
if len(matching) >= rule.threshold:
self.alerts.append({
"rule": rule.name,
"severity": rule.severity,
"matched_events": len(matching),
"timestamp": datetime.now().isoformat()
})
return self.alerts
def _matches(self, event: Dict, query: str) -> bool:
# 간단한 쿼리 매칭 (실제로는 복잡한 DSL 파싱)
field, value = query.split("=")
return event.get(field.strip()) == value.strip()
# 브루트포스 공격 탐지 룰 예시
brute_force_rule = SIEMRule(
name="SSH Brute Force Detection",
description="5분 내 동일 IP에서 10회 이상 SSH 실패",
query="event_type = ssh_failed",
threshold=10,
time_window=timedelta(minutes=5),
severity="HIGH"
)
박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다. "SIEM을 이해하려면 먼저 전체 그림을 봐야 해요." 서버, 방화벽, 애플리케이션 등 여러 시스템에서 로그가 쏟아져 나옵니다.
이걸 사람이 일일이 본다면? 하루에 수백만 건의 로그를 확인하는 건 불가능합니다.
SIEM은 이 모든 로그를 한곳에 모아서 분석합니다. 마치 도시 전체의 CCTV를 한 관제실에서 보는 것과 같습니다.
하지만 CCTV만 있다고 범인을 잡을 수 있는 게 아니듯, SIEM도 탐지 룰이 있어야 제 역할을 합니다. 탐지 룰은 "이런 상황이 발생하면 경보를 울려라"라는 규칙입니다.
예를 들어 "5분 안에 같은 IP에서 SSH 로그인이 10번 이상 실패하면 브루트포스 공격일 수 있다"라는 룰을 만들 수 있습니다. 코드의 SIEMRule 클래스가 바로 이 룰을 표현합니다.
코드에서 주목할 부분은 threshold와 time_window입니다. 임계값이 너무 낮으면 정상적인 활동도 경보로 울립니다.
이걸 **오탐(False Positive)**이라고 합니다. 반대로 임계값이 너무 높으면 실제 공격을 놓칩니다.
이건 **미탐(False Negative)**입니다. 적절한 균형점을 찾는 게 룰 튜닝의 핵심입니다.
실무에서 SIEM 룰을 작성할 때 가장 중요한 건 정상 패턴을 먼저 이해하는 것입니다. 우리 시스템에서 평소에 어떤 활동이 얼마나 일어나는지 모르면, 비정상을 판단할 기준이 없습니다.
그래서 새 룰을 배포하기 전에 먼저 테스트 모드로 돌려보고, 오탐률을 확인한 뒤 임계값을 조정합니다. 좋은 SIEM 룰에는 몇 가지 특징이 있습니다.
첫째, 구체적인 컨텍스트를 활용합니다. 단순히 "로그인 실패"가 아니라 "동일 IP에서 여러 계정으로 로그인 시도"처럼 더 정교하게 정의합니다.
둘째, 예외 처리가 잘 되어 있습니다. 모니터링 시스템이 정기적으로 상태 확인하는 것까지 경보로 울리면 안 되니까요.
김개발 씨가 첫 번째 룰을 작성하고 배포했습니다. 다음 날 아침, 경보가 5건 발생했습니다.
확인해보니 3건은 실제 스캔 공격이었고, 2건은 비밀번호를 잊은 직원의 로그인 시도였습니다. 오탐률 40%는 좀 높았습니다.
"임계값을 10에서 15로 올려볼까요?" 튜닝 작업이 시작되었습니다.
실전 팁
💡 - 새 룰은 반드시 테스트 모드로 1-2주 운영한 뒤 오탐률을 확인하고 배포하세요
- 화이트리스트를 활용해 알려진 정상 활동(모니터링 시스템, 배치 작업 등)은 제외하세요
- MITRE ATT&CK 프레임워크를 참고하면 체계적인 탐지 룰을 설계할 수 있습니다
4. 위협 헌팅 쿼리 개발
어느 날 보안 뉴스에서 새로운 해킹 기법이 보도되었습니다. "우리 시스템에도 이미 침투했으면 어떡하지?" 이보안 씨의 걱정에 박시니어 씨가 답했습니다.
"SIEM 룰은 알려진 패턴을 탐지해요. 하지만 아직 모르는 위협을 찾으려면 직접 사냥을 나가야 합니다.
그게 바로 위협 헌팅이에요."
**위협 헌팅(Threat Hunting)**은 시스템에 이미 침투했을지 모르는 위협을 능동적으로 찾아내는 활동입니다. 마치 형사가 사건 현장에서 단서를 찾듯이, 로그와 이벤트 속에서 수상한 흔적을 추적합니다.
자동 탐지를 보완하는 인간 주도의 보안 활동으로, 가설을 세우고 검증하는 과학적 방법론을 따릅니다.
다음 코드를 살펴봅시다.
from datetime import datetime, timedelta
from typing import List, Dict, Any
import json
class ThreatHunter:
def __init__(self, log_source):
self.log_source = log_source
self.findings: List[Dict] = []
def hunt_lateral_movement(self, time_range: timedelta) -> List[Dict]:
# 가설: 공격자가 내부망에서 횡적 이동 중일 수 있다
# 지표: 짧은 시간 내 여러 서버로 인증 시도
query = """
SELECT source_ip, COUNT(DISTINCT dest_host) as host_count
FROM auth_logs
WHERE timestamp > NOW() - INTERVAL '1 hour'
GROUP BY source_ip
HAVING COUNT(DISTINCT dest_host) > 5
"""
results = self.log_source.execute(query)
for row in results:
if row['host_count'] > 5:
self.findings.append({
"hypothesis": "Lateral Movement",
"indicator": f"IP {row['source_ip']} accessed {row['host_count']} hosts",
"confidence": "MEDIUM",
"next_steps": ["Check if legitimate admin", "Review accessed systems"]
})
return self.findings
def hunt_data_exfiltration(self) -> List[Dict]:
# 가설: 대량의 데이터가 외부로 유출되고 있을 수 있다
query = """
SELECT source_ip, dest_ip, SUM(bytes_out) as total_bytes
FROM network_flows
WHERE dest_ip NOT IN (SELECT ip FROM internal_networks)
AND timestamp > NOW() - INTERVAL '24 hours'
GROUP BY source_ip, dest_ip
HAVING SUM(bytes_out) > 1073741824
"""
# 1GB 이상 외부 전송 탐지
return self.log_source.execute(query)
SIEM 룰이 아무리 잘 만들어져 있어도 한계가 있습니다. 룰은 이미 알려진 패턴만 탐지할 수 있기 때문입니다.
만약 공격자가 완전히 새로운 방법을 사용한다면? 아니면 정상적인 활동처럼 위장한다면?
이런 위협은 자동화된 시스템으로 잡기 어렵습니다. 그래서 위협 헌팅이 필요합니다.
위협 헌팅은 마치 숲에서 사냥감을 찾는 것과 같습니다. 명확한 표적이 있는 게 아니라, "분명 어딘가에 있을 것이다"라는 가설을 세우고 흔적을 추적합니다.
이 과정은 과학적 방법론을 따릅니다. 가설 수립, 데이터 수집, 분석, 검증의 사이클을 반복합니다.
코드의 hunt_lateral_movement 함수를 봅시다. 여기서 가설은 "공격자가 내부망에서 횡적 이동 중일 수 있다"입니다.
공격자가 한 시스템을 장악한 뒤 다른 시스템으로 확산하는 패턴이죠. 이 가설을 검증하기 위해 짧은 시간 내 여러 서버에 인증을 시도한 IP를 찾습니다.
SQL 쿼리를 보면, 1시간 동안 5개 이상의 서로 다른 호스트에 접근한 IP를 찾고 있습니다. 일반적인 사용자는 이렇게 많은 서버에 연속으로 접근하지 않습니다.
물론 시스템 관리자나 모니터링 도구일 수도 있으니, next_steps에 추가 확인 작업을 명시했습니다. hunt_data_exfiltration 함수는 데이터 유출을 탐지합니다.
24시간 동안 외부로 1GB 이상 데이터를 전송한 경우를 찾습니다. 정상적인 백업이나 클라우드 동기화일 수도 있지만, 악성 행위자가 데이터를 빼돌리는 것일 수도 있습니다.
위협 헌팅에서 가장 중요한 건 컨텍스트입니다. 같은 행위라도 누가, 언제, 어떤 상황에서 했느냐에 따라 정상일 수도 있고 악의적일 수도 있습니다.
그래서 헌팅 결과는 항상 **조사(investigation)**로 이어져야 합니다. 김개발 씨가 첫 헌팅 쿼리를 돌려보았습니다.
결과에 IP 하나가 나왔는데, 확인해보니 데브옵스 팀의 젠킨스 서버였습니다. 배포 과정에서 여러 서버에 접근하는 정상적인 활동이었죠.
"오탐이네요." 하지만 실망할 필요 없습니다. 이런 과정을 통해 정상 기준선이 명확해지고, 다음에는 젠킨스를 제외하고 검색할 수 있습니다.
실전 팁
💡 - MITRE ATT&CK 프레임워크의 TTP(Tactics, Techniques, Procedures)를 참고해 헌팅 가설을 수립하세요
- 헌팅 결과와 과정은 반드시 문서화하여 팀 내 지식으로 축적하세요
- 정기적인 헌팅 스케줄을 수립하고, 위협 인텔리전스 피드를 활용해 최신 공격 기법을 반영하세요
5. 보안 대시보드 구축
이제 스캐너도 있고, SIEM 룰도 있고, 헌팅 쿼리도 있습니다. 하지만 경영진 미팅에서 CISO가 물었습니다.
"그래서 우리 보안 상태가 어떤 건가요? 한눈에 볼 수 있는 화면 없어요?" 숫자와 로그 더미를 보여줄 수는 없었습니다.
복잡한 보안 데이터를 직관적으로 보여주는 대시보드가 필요했습니다.
보안 대시보드는 조직의 보안 상태를 시각화하여 한눈에 파악할 수 있게 해주는 도구입니다. 마치 자동차 계기판처럼 속도, 연료량, 엔진 상태를 한 번에 보여주듯이, 보안 대시보드는 위협 수준, 취약점 현황, 인시던트 통계 등 핵심 지표를 시각화합니다.
기술팀과 경영진 모두에게 유용한 커뮤니케이션 도구입니다.
다음 코드를 살펴봅시다.
from dataclasses import dataclass
from typing import List, Dict
from datetime import datetime, timedelta
from collections import Counter
@dataclass
class SecurityMetric:
name: str
value: float
trend: str # up, down, stable
severity: str # critical, high, medium, low
class SecurityDashboard:
def __init__(self, data_sources: Dict):
self.sources = data_sources
self.metrics: List[SecurityMetric] = []
def calculate_risk_score(self) -> SecurityMetric:
# 전체 보안 위험도 점수 계산 (0-100)
vuln_count = self.sources['vulnerabilities'].get_count()
open_incidents = self.sources['incidents'].get_open_count()
failed_logins = self.sources['auth'].get_failed_count(hours=24)
# 가중치 적용 점수 계산
score = 100 - (vuln_count * 2 + open_incidents * 5 + failed_logins * 0.1)
score = max(0, min(100, score)) # 0-100 범위로 제한
return SecurityMetric(
name="Overall Security Score",
value=score,
trend=self._calculate_trend('risk_score'),
severity="critical" if score < 50 else "medium"
)
def get_vulnerability_summary(self) -> Dict:
# 취약점 심각도별 분포
vulns = self.sources['vulnerabilities'].get_all()
severity_counts = Counter(v['severity'] for v in vulns)
return {
"critical": severity_counts.get("CRITICAL", 0),
"high": severity_counts.get("HIGH", 0),
"medium": severity_counts.get("MEDIUM", 0),
"total": len(vulns)
}
def get_incident_timeline(self, days: int = 7) -> List[Dict]:
# 일별 인시던트 발생 추이
incidents = self.sources['incidents'].get_recent(days)
daily_counts = Counter(i['date'].date() for i in incidents)
return [{"date": str(d), "count": c} for d, c in sorted(daily_counts.items())]
박시니어 씨가 말했습니다. "데이터는 많은데 인사이트가 없으면 무용지물이에요.
대시보드는 데이터를 정보로, 정보를 인사이트로 바꿔주는 도구입니다." 좋은 보안 대시보드의 첫 번째 요소는 **핵심 지표(KPI)**입니다. 모든 데이터를 다 보여주려 하면 안 됩니다.
가장 중요한 몇 가지 지표만 선별해야 합니다. 코드의 calculate_risk_score가 대표적입니다.
취약점 수, 열린 인시던트 수, 로그인 실패 횟수를 종합해서 하나의 점수로 만들었습니다. 두 번째 요소는 **추세(Trend)**입니다.
현재 값만큼 중요한 게 "좋아지고 있나, 나빠지고 있나"입니다. SecurityMetric의 trend 필드가 이 역할을 합니다.
점수가 70점이라도 어제보다 10점 떨어졌다면 주의가 필요합니다. 세 번째는 드릴다운(Drill-down) 기능입니다.
전체 점수를 보다가 "왜 이렇게 낮지?"라는 의문이 들면, 클릭해서 세부 내용을 볼 수 있어야 합니다. get_vulnerability_summary가 이런 세부 정보를 제공합니다.
대시보드를 설계할 때 흔히 하는 실수가 있습니다. 너무 많은 정보를 담으려는 것입니다.
경영진용 대시보드와 보안팀용 대시보드는 달라야 합니다. 경영진은 "우리가 안전한가?"를 알고 싶고, 보안팀은 "어디를 고쳐야 하나?"를 알고 싶습니다.
get_incident_timeline 함수는 시간에 따른 변화를 보여줍니다. 인시던트가 갑자기 급증했다면 뭔가 문제가 생긴 것입니다.
이런 패턴은 숫자 목록보다 그래프로 보면 훨씬 직관적으로 파악됩니다. 실무에서는 Grafana, Kibana, Splunk 같은 도구를 많이 사용합니다.
하지만 이런 도구를 쓰더라도 어떤 지표를 어떻게 보여줄지는 직접 설계해야 합니다. 코드로 메트릭을 계산하는 로직을 이해하면, 어떤 도구를 쓰든 좋은 대시보드를 만들 수 있습니다.
김개발 씨가 만든 대시보드를 CISO에게 보여드렸습니다. "오, 이거 좋네요.
현재 보안 점수가 72점이고, 지난주보다 5점 올랐군요. 중요 취약점이 아직 3개 남았는데, 이건 언제 해결되나요?" 대화가 숫자에서 행동으로 이어지기 시작했습니다.
실전 팁
💡 - 대시보드에는 실행 가능한 정보만 담으세요. "예쁜" 그래프보다 "유용한" 그래프가 중요합니다
- 실시간 대시보드와 주간/월간 리포트를 구분하세요. 목적에 따라 보여줄 내용이 다릅니다
- 알림 임계값을 대시보드에 시각적으로 표시하면 현재 상태가 정상인지 즉시 파악할 수 있습니다
6. 인시던트 대응 플레이북 자동화
새벽 3시, 김개발 씨의 전화가 울렸습니다. "SIEM에서 경보가 떴어요.
랜섬웨어 같은데..." 잠이 덜 깬 상태로 노트북을 켰지만, 머리가 하얘졌습니다. "일단 뭘 해야 하지?" 이런 상황에서 당황하지 않고 체계적으로 대응하려면 플레이북이 필요합니다.
그리고 반복적인 작업은 자동화해야 합니다.
인시던트 대응 플레이북은 보안 사고 발생 시 따라야 할 단계별 절차를 정리한 문서입니다. 마치 비행기 조종사의 체크리스트처럼, 긴급 상황에서도 빠뜨리는 것 없이 대응할 수 있게 해줍니다.
여기에 자동화를 더하면 초기 대응 시간을 분 단위에서 초 단위로 줄일 수 있습니다. 이것이 바로 **SOAR(Security Orchestration, Automation and Response)**의 핵심입니다.
다음 코드를 살펴봅시다.
from enum import Enum
from dataclasses import dataclass
from typing import List, Callable, Dict, Any
from datetime import datetime
import subprocess
class IncidentType(Enum):
MALWARE = "malware"
BRUTE_FORCE = "brute_force"
DATA_LEAK = "data_leak"
PHISHING = "phishing"
@dataclass
class PlaybookStep:
name: str
action: Callable
auto_execute: bool
requires_approval: bool
class IncidentPlaybook:
def __init__(self, incident_type: IncidentType):
self.incident_type = incident_type
self.steps: List[PlaybookStep] = []
self.execution_log: List[Dict] = []
def add_step(self, step: PlaybookStep):
self.steps.append(step)
def execute(self, context: Dict[str, Any]):
# 플레이북 단계별 실행
for step in self.steps:
self._log(f"Starting: {step.name}")
if step.requires_approval:
if not self._get_approval(step.name):
self._log(f"Skipped (not approved): {step.name}")
continue
try:
result = step.action(context)
self._log(f"Completed: {step.name}", result)
except Exception as e:
self._log(f"Failed: {step.name}", str(e))
raise
# 자동 대응 액션 정의
def isolate_host(context: Dict) -> str:
# 감염 호스트 네트워크 격리
host_ip = context['affected_host']
# 방화벽 룰 추가로 해당 IP 차단
return f"Host {host_ip} isolated from network"
def collect_forensics(context: Dict) -> str:
# 포렌식 데이터 수집 (메모리 덤프, 로그 등)
host = context['affected_host']
return f"Forensic data collected from {host}"
def notify_team(context: Dict) -> str:
# 보안팀 및 관련자 알림
return "Incident notification sent to security team"
# 멀웨어 대응 플레이북 구성
malware_playbook = IncidentPlaybook(IncidentType.MALWARE)
malware_playbook.add_step(PlaybookStep("Isolate Host", isolate_host, auto_execute=True, requires_approval=False))
malware_playbook.add_step(PlaybookStep("Collect Forensics", collect_forensics, auto_execute=True, requires_approval=False))
malware_playbook.add_step(PlaybookStep("Notify Team", notify_team, auto_execute=True, requires_approval=False))
보안 인시던트가 발생하면 모든 것이 빠르게 돌아갑니다. 공격자는 몇 분 안에 시스템을 장악하고 데이터를 빼갈 수 있습니다.
이런 상황에서 "일단 뭘 해야 하지?"라고 고민하면 이미 늦습니다. 플레이북은 미리 정해둔 대응 절차입니다.
비행기 조종사를 생각해보세요. 엔진에 문제가 생기면 당황하지 않고 체크리스트를 꺼냅니다.
수천 번 훈련한 절차를 하나씩 따라갑니다. 보안 플레이북도 마찬가지입니다.
랜섬웨어가 발견되면? 1단계: 감염 호스트 격리.
2단계: 포렌식 데이터 수집. 3단계: 관련자 알림.
이런 식으로 미리 정해둡니다. 코드의 IncidentPlaybook 클래스가 이 구조를 구현합니다.
PlaybookStep은 각 단계를 나타내고, auto_execute와 requires_approval 플래그로 자동 실행 여부와 승인 필요 여부를 결정합니다. 왜 자동화가 중요할까요?
첫째, 속도입니다. 감염 호스트를 수동으로 격리하려면 방화벽에 로그인하고, 룰을 찾고, 새 룰을 추가하고...
5분이 훌쩍 지나갑니다. 자동화하면 5초면 됩니다.
둘째, 일관성입니다. 사람은 긴장하면 실수합니다.
스크립트는 늘 같은 방식으로 동작합니다. isolate_host 함수를 보세요.
감염된 호스트의 IP를 받아서 네트워크에서 격리합니다. 실제로는 방화벽 API를 호출하거나 네트워크 장비에 명령을 보내겠지만, 여기서는 개념만 보여주고 있습니다.
중요한 건 이 작업이 프로그래밍적으로 가능하다는 것입니다. collect_forensics는 증거 수집입니다.
나중에 어떻게 침투했는지, 무슨 짓을 했는지 분석하려면 로그와 메모리 덤프가 필요합니다. 이것도 호스트가 격리된 직후 바로 수집해야 합니다.
시간이 지나면 증거가 사라지거나 덮어씌워질 수 있거든요. 주의할 점도 있습니다.
모든 것을 자동화하면 위험합니다. 잘못된 경보에 자동으로 호스트를 격리하면 서비스 장애가 발생합니다.
그래서 requires_approval 옵션이 있습니다. 중요한 결정은 사람이 확인한 뒤 실행하도록 설정할 수 있습니다.
다시 새벽 3시의 김개발 씨로 돌아가 봅시다. 이제는 당황하지 않습니다.
SIEM 경보가 뜨자 자동으로 플레이북이 실행됩니다. 감염 호스트가 격리되고, 포렌식 데이터 수집이 시작되고, 팀에 알림이 갑니다.
김개발 씨가 해야 할 일은 이미 수집된 데이터를 분석하고 다음 단계를 결정하는 것뿐입니다.
실전 팁
💡 - 플레이북은 인시던트 유형별로 따로 만드세요. 랜섬웨어와 피싱은 대응 방법이 다릅니다
- 모든 플레이북 실행은 상세 로그로 남겨야 합니다. 나중에 사후 분석과 개선에 필수입니다
- 정기적으로 테이블탑 훈련을 실시해서 플레이북이 현실에 맞는지 검증하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
최신 보안 트렌드 완벽 가이드
AI 기반 보안 시스템부터 제로 트러스트, 블록체인 보안까지. 2024년 현업에서 반드시 알아야 할 최신 보안 트렌드를 초급 개발자도 이해할 수 있도록 실무 예제와 함께 설명합니다.
Context Optimization 컨텍스트 최적화 기법
AI 에이전트와 대규모 언어 모델 활용 시 컨텍스트 윈도우를 효율적으로 관리하는 방법을 다룹니다. 토큰 비용 절감부터 캐시 최적화까지, 실무에서 바로 적용할 수 있는 핵심 기법들을 소개합니다.
클라우드 보안 실전 완벽 가이드
AWS, Docker, Kubernetes 환경에서 보안을 자동화하고 취약점을 사전에 탐지하는 방법을 알아봅니다. 초급 개발자도 바로 적용할 수 있는 실전 보안 점검 스크립트와 CI/CD 파이프라인 보안 구축 방법을 다룹니다.
Memory Systems 에이전트 메모리 아키텍처 완벽 가이드
AI 에이전트가 정보를 기억하고 활용하는 메모리 시스템의 핵심 아키텍처를 다룹니다. 벡터 스토어의 한계부터 Knowledge Graph, Temporal Knowledge Graph까지 단계별로 이해할 수 있습니다.
Phase 5 취약점 발굴과 분석 완벽 가이드
보안 전문가가 되기 위한 취약점 발굴의 핵심 기법을 다룹니다. 코드 리뷰부터 퍼징, 바이너리 분석까지 실무에서 바로 활용할 수 있는 기술을 초급자 눈높이에 맞춰 설명합니다.