서론
2024년 3월, 어느 대형 금융회사의 보안팀은 긴급 회의 소집 명령을 받았다. 최근 공개된 Apache 로그 제로데이 취약점에 대한 대응이 필요했다. 그러나 NVD(National Vulnerability Database)에서 해당 CVE의 CVSS 점수와 영향 분석을 조회하려던 보안팀은 당황할 수밖에 없었다. 등록된 지 수주일이 지났음에도 상세 분석 데이터가 비어 있었기 때문이다.
이것은 특정 기업만의 문제가 아니다. 전 세계 보안 실무자들이 동일한 현상을 겪고 있었다. NVD의 처리 지연은 이미 업계의 공공연한 비밀이 되었고, 그 배경에는 폭증하는 CVE 등록 물량이라는 구조적 문제가 자리 잡고 있었다.
미국 국립표준기술연구소(NIST)가 운영하는 NVD는 전 세계 사이버 보안 생태계의 기둥과 같은 존재다. 모든 CVE 취약점에 대해 CVSS 점수, 취약점 유형, 영향을 받는 소프트웨어 버전 등 핵심 데이터를 제공하는 공식 데이터베이스다. 기업의 취약점 관리 프로세스, 상용 보안 스캐너의 탐지 로직, 자동화된 패치 관리 시스템 모두 이 데이터에 의존한다.
그러나 2023년 이후 CVE 등록 건수는 기하급수적으로 증가했고, 기존의 “모든 취약점을 동일하게 분석"하는 방식은 한계에 직면했다. NIST가 선택한 해답은 Risk-based Triage, 즉 위험 기반 우선순위 분류 체계의 도입이었다.
본론
NVD의 구조적 한계와 처리 지연의 원인
NVD의 처리 지연 문제를 이해하려면 먼저 CVE 생태계의 구조를 살펴야 한다. CVE(Number)는 MITRE가 관리하는 식별자 체계이고, NVD는 NIST가 운영하는 상세 분석 데이터베이스다. 새로운 취약점이 발견되면 CVE 번호가 먼저 할당되고, 이후 NVD에서 CVSS 점수 등 상세 분석이 추가되는 구조다.
문제는 이 “상세 분석” 작업에 드는 시간과 리소스다. 숙련된 분석가가 하나의 CVE를 완전히 분석하려면 평균 30분에서 2시간이 소요된다. 소프트웨어 체인이 복잡한 경우 더 오래 걸린다.
1
2
3
4
5
6
7
| graph LR
A[취약점 발견] --> B[CVE 번호 할당]
B --> C[NVD 분석 대기]
C --> D[CVE 상세 분석]
D --> E[CVSS 점수 산정]
E --> F[NVD 데이터베이스 등록]
F --> G[보안 도구 업데이트]
|
CVE 등록 물량의 기하급수적 증가 추세
최근 5년간 CVE 등록 건수는 폭발적으로 증가했다. 오픈소스 소프트웨어 사용량 증가, 클라우드 네이티브 환경의 복잡성, 그리고 취약점 연구 커뮤니티의 성장이 주요 원인이다.
| 연도 | 연간 CVE 등록 건수 | NVD 분석 완료율 | 평균 분석 소요 시간 | | :— | :—: | :—: | :—: | | 2020년 | 18,352건 | 98% | 7일 | | 2021년 | 20,171건 | 97% | 12일 | | 2022년 | 25,067건 | 94% | 21일 | | 2023년 | 28,400건 | 78% | 56일 | | 2024년(추정) | 34,000건 이상 | 60% 미만 | 90일 이상 |
표에서 알 수 있듯, 2023년부터 분석 완료율이 급격히 하락하고 처리 시간이 폭증했다. 이는 곧 보안 실무자들이 “CVSS 점수 없이 취약점을 평가해야 하는” 상황으로 직결된다.
Risk-based Triage의 핵심 원리
NIST가 발표한 Risk-based Triage는 모든 취약점을 동일한 깊이로 분석하는 대신, 실제 위험도에 따라 분석 깊이와 우선순위를 차등화하는 방식이다.
1
2
3
4
5
6
7
8
| graph TD
A[CVE 접수] --> B{자동화된 1차 평가}
B -->|고위험| C[즉시 심층 분석]
B -->|중위험| D[표준 분석 큐]
B -->|저위험| E[최소 분석 또는 보류]
C --> F[24시간 내 CVSS 산정]
D --> G[30일 내 CVSS 산정]
E --> H[필요시 재평가]
|
이 체계의 핵심은 자동화된 1차 평가(Triage) 단계다. 다음 요소들이 종합적으로 고려된다:
- 영향을 받는 소프트웨어의 보급률: Apache, Nginx 등 널리 사용되는 소프트웨어일수록 높은 우선순위 2. 인터넷 노출 가능성: 원격 접근 가능한 취약점인지, 로컬 접근이 필요한지 3. 이미 확인된 익스플로잇 존재 여부: 공개된 PoC나 실제 공격 사례가 있는지 4. 공급망 영향 범위: 단일 제품인지, 라이브러리를 통해 광범위하게 영향을 미치는지
자동화된 위험 평가 스크립트 예시
보안 실무자들은 NVD의 Triage 체계가 완전히 가동될 때까지, 자체적인 우선순위 평가 로직을 구축해야 한다. 다음은 CVE 정보를 기반으로 간단한 위험도 평가를 수행하는 Python 스크립트 예시다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| import requests
from datetime import datetime, timedelta
class CVETriage:
"""NVD 처리 지연 대응을 위한 자체 위험 평가 클래스"""
def __init__(self, cve_id):
self.cve_id = cve_id
self.cve_data = self._fetch_cve_data()
def _fetch_cve_data(self):
"""NVD API에서 CVE 데이터 조회"""
url = f"https://services.nvd.nist.gov/rest/json/cves/2.0?cveId={self.cve_id}"
headers = {"apiKey": "YOUR_API_KEY"}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"[ERROR] API 조회 실패: {e}")
return None
def assess_risk_level(self):
"""다양한 요소를 종합한 위험도 평가"""
if not self.cve_data:
return "UNKNOWN", "데이터 조회 실패"
risk_score = 0
reasons = []
# 1. CVSS 점수 확인 (NVD에서 이미 산정한 경우)
metrics = self.cve_data.get("vulnerabilities", [{}])[0].get("cve", {}).get("metrics", {})
if "cvssMetricV31" in metrics:
cvss_score = metrics["cvssMetricV31"][0]["cvssData"]["baseScore"]
if cvss_score >= 9.0:
risk_score += 40
reasons.append(f"Critical CVSS: {cvss_score}")
elif cvss_score >= 7.0:
risk_score += 25
reasons.append(f"High CVSS: {cvss_score}")
else:
# CVSS 점수가 없으면 공지된 심각도 확인
risk_score += 15
reasons.append("CVSS 미산정 - 수동 평가 필요")
# 2. 공개된 지 얼마나 되었는지 (최근일수록 위험)
published = self.cve_data.get("vulnerabilities", [{}])[0].get("cve", {}).get("published", "")
if published:
pub_date = datetime.fromisoformat(published.replace("Z", "+00:00"))
days_old = (datetime.now(pub_date.tzinfo) - pub_date).days
if days_old <= 7:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
risk_score += 20
reasons.append(f"최근 공개: {days_old}일 전")
elif days_old <= 30:
risk_score += 10
# 3. 영향받는 제품 수 (CPE 정보 기반)
configurations = self.cve_data.get("vulnerabilities", [{}])[0].get("cve", {}).get("configurations", [])
affected_products = set()
for config in configurations:
for node in config.get("nodes", []):
for cpe in node.get("cpeMatch", []):
criteria = cpe.get("criteria", "")
if "apache" in criteria.lower() or "nginx" in criteria.lower():
risk_score += 15
reasons.append("주요 인프라 소프트웨어 영향")
break
# 4. 익스플로잇 가능성 지표 (참고 정보)
references = self.cve_data.get("vulnerabilities", [{}])[0].get("cve", {}).get("references", [])
for ref in references:
url = ref.get("url", "").lower()
if "exploit" in url or "poc" in url or "github.com" in url:
risk_score += 25
reasons.append("공개 익스플로잇/POC 확인됨")
break
# 위험 등급 산정
if risk_score >= 70:
return "CRITICAL", "; ".join(reasons)
elif risk_score >= 40:
return "HIGH", "; ".join(reasons)
elif risk_score >= 20:
return "MEDIUM", "; ".join(reasons)
else:
return "LOW", "; ".join(reasons)
# 실행 예시
if __name__ == "__main__":
triage = CVETriage("CVE-2024-3094") # XZ Utils 백도어 취약점
level, detail = triage.assess_risk_level()
print(f"[{level}] {triage.cve_id}")
print(f"평가 근거: {detail}")
|
이 스크립트는 NVD 데이터가 완전하지 않을 때 보안팀이 자체적으로 1차 위험 평가를 수행할 수 있도록 돕는다. 실제 운영 환경에서는 EPSS(Exploit Prediction Scoring System), CISA KEV(Known Exploited Vulnerabilities) 카탈로그, 그리고 자산 중요도 정보를 추가로 통합해야 한다.
보안 실무자를 위한 Step-by-Step 대응 가이드
NVD의 변화는 보안 프로세스 전반에 영향을 미친다. 다음은 즉시 실행 가능한 대응 가이드다.
1단계: NVD 의존도 진단
현재 조직의 취약점 관리 프로세스가 NVD 데이터에 얼마나 의존하고 있는지 평가한다. 상용 스캐너(Nessus, Qualys, Rapid7 등)의 NVD 연동 방식, 자동화된 패치 배포 기준, 컴플라이언스 보고서 생성 로직을 점검한다.
2단계: 다중 데이터 소스 확보
NVD 단일 소스에 의존하지 않는 아키텍처를 구축한다. GitHub Advisory Database, 상용 취약점 인텔리전스 서비스, 소프트웨어 벤더 자체 보안 공지, CISA KEV 카탈로그를 병행 활용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 다중 소스 취약점 정보 통합 예시
SOURCES = {
"nvd": "https://services.nvd.nist.gov/rest/json/cves/2.0",
"github": "https://api.github.com/advisories",
"cisa_kev": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog"
}
def aggregate_vulnerability_data(cve_id):
"""다중 소스에서 취약점 정보를 취합하는 함수"""
aggregated = {"cve_id": cve_id, "sources": {}}
for source_name, base_url in SOURCES.items():
try:
data = fetch_from_source(source_name, base_url, cve_id)
aggregated["sources"][source_name] = data
except Exception:
aggregated["sources"][source_name] = {"status": "unavailable"}
# 가장 높은 위험 평가를 기준으로 채택
return aggregated
|
3단계: 자산 기반 위험 평가 체계 구축
NVD의 CVSS 점수가 지연되더라도 조직 내부적으로 패치 우선순위를 결정할 수 있는 체계가 필요하다. 자산 중요도, 네트워크 노출 여부, 비즈니스 영향도를 기반으로 한 내부 평가 매트릭스를 구축한다.
4단계: 자동화된 모니터링 강화
NVD 데이터 업데이트를 지속적으로 모니터링하고, CVSS 점수가 산정되었을 때 즉시 반영할 수 있는 자동화 파이프라인을 구축한다. webhook 기반 알림, 정기 폴링 스크립트, SIEM 연동 등의 방법을 활용한다.
5단계: 임시 평가 기준 문서화
NVD 분석이 지연되는 기간 동안 사용할 임시 취약점 평가 기준을 문서화하고 관련진에게 공유한다. 이 기준에는 취약점 발표 초기 정보, 벤더 자체 심각도 평가, 커뮤니티 피드백을 반영한다.
Risk-based Triage가 가져올 장단점
| 측면 | 기존 방식 (동일 분석) | Risk-based Triage | | :— | :— | :— | | 분석 속도 | 모든 CVE에 동일한 시간 소요 | 고위험 CVE 우선 처리로 신속 대응 | | 분석 완전성 | 모든 CVE에 대한 완전한 분석 보장 | 저위험 CVE는 최소 분석 가능성 | | 실무 활용성 | 중요도와 무관한 지연 발생 | 실제 위협에 대한 정보가 빠르게 제공됨 | | 프로세스 복잡성 | 단순한 FIFO 구조 | Triage 로직 자체의 검증 필요 | | 데이터 일관성 | 균일한 품질 보장 | 분석 깊이 차이로 인한 정보 격차 가능성 |
결론
핵심 요약
NIST의 Risk-based Triage 도입은 NVD의 구조적
출처: https://news.google.com/rss/articles/CBMizAFBVV95cUxNUUdXUkNMbGoycXBubnVwYUVMUXZjcURkbHhQRm5wTFZXLW1GS1EydDUybEdROFdZTm1Td090SkdRUVBLUkZUcllhUGQ5NFlGSnNoUVY2UU0wVS1PQ19OT2t2b1Azak1QRlNKLXNJNlo5Xzk2UFB4TWlVd09sWmZPbzdzNXNmaFBneWpuNHQ1bU1ZRHhJa0RGaVhDMm44ekZWdDh2M1dPNmprTTd2UEVWQnZ6NUhpbDBXQjZaUWp0NGpqczRwVUJoNjltNUw?oc=5