剣 KENSAI
사례 연구

B등급에서 B등급 A등급으로 A등급:
30분 만에 NIS2 규정 준수를 개선한 방법

KENSAI로 자체 웹사이트를 검사한 결과 중대한 NIS2 규정 준수 공백을 발견했습니다. HTTP 보안 헤더가 누락돼 세 도메인 중 두 곳의 등급이 B(0.786)로 떨어져 있었습니다. 무엇이 잘못됐고, NIS2의 어느 조항이 위험했으며, Caddy 설정을 30분 수정해 어떻게 모두 해결했는지 자세히 설명합니다.

📅 2026년 3월 16일 ⏱ 읽는 시간 6분 🏷 NIS2 · 규정 준수 · 사례 연구 · Caddy

불편한 진실

우리는 보안 검사 플랫폼을 만들고 고객에게 NIS2 규정 준수를 강조합니다. 그런데 자체 도메인에 KENSAI를 실행해 보니 세 곳 중 두 곳이 규정을 충족하지 못하고 있었습니다.

취약점도 침해도 없었습니다. 단지 HTTP 보안 헤더가 빠져 있었습니다. 규제기관이 먼저 확인하고 공격자가 그다음 노리는, 눈에 띄지 않는 공백입니다. NIS2 지침 제21조 제2항에 따라 규제 대상 기관에 이 헤더는 선택 사항이 아니라 기본 보안 위생 요건입니다.

무엇을 발견했고 얼마나 빨리 고쳤는지 살펴보겠습니다.


검사 결과

2026년 3월 15일, 포트폴리오의 세 도메인 모두에 KENSAI 자동 NIS2 규정 준수 검사를 실행했습니다.

kensai.app
A
0.997 / 1.000
NIS2 점수
brnz.ai
B
0.786 / 1.000
NIS2 점수
codeforceai.com
B
0.786 / 1.000
NIS2 점수

kensai.app 점수는 올바른 Caddy 헤더 설정이 이미 적용돼 0.997로 거의 만점에 가까웠습니다. 나머지 두 도메인인 brnz.aicodeforceai.com 두 곳은 모두 0.786점이었고, 동일한 핵심 보안 헤더 여섯 개가 빠져 있었습니다.


누락된 항목과 NIS2에서 중요한 이유

문제가 있던 두 도메인 모두 HTTP 응답 헤더 여섯 개가 없었습니다. 각 헤더는 NIS2 지침의 요건과 직접 연결됩니다.

누락된 헤더 목적 NIS2 근거 상태
Strict-Transport-Security HTTPS를 강제하고 프로토콜 다운그레이드 공격 방지 제21조 제2항 h호 — 안전한 통신 ✗ 누락
Content-Security-Policy XSS, 코드 삽입, 데이터 유출 차단 제21조 제2항 d호 — 공급망 보안 ✗ 누락
X-Frame-Options 클릭재킹 및 UI 위장 공격 방지 제21조 제2항 b호 — 사고 예방 ✗ 누락
X-Content-Type-Options MIME 스니핑 공격 차단 제21조 제2항 b호 — 기본 사이버 위생 ✗ 누락
Referrer-Policy 제3자에게 유출되는 리퍼러 데이터 제어 제21조 제2항 e호 — 데이터 보안 정책 ✗ 누락
Permissions-Policy 브라우저 API 접근 제한(카메라, 마이크, 위치 정보) 제25조 — 설계 단계부터의 보안 ✗ 누락
NIS2에 미치는 영향: 제21조 제2항에 따라 규제 대상 기관은 “적절하고 비례적인 기술적·조직적 조치”를 시행해야 합니다. HSTS가 없으면 암호화되지 않은 연결이 가능하고, CSP가 없으면 XSS 공격으로 데이터가 유출될 수 있습니다. 국가 관할기관은 이를 기본 보안이 부족하다는 증거로 봅니다.
제21조와 제25조가 요구하는 사항: 제21조는 네트워크 보안 및 접근 통제 정책을 포함한 위험 관리 조치를 의무화합니다. 제25조는 보안 통제를 사후 대응이 아니라 선제적으로 적용하는 “설계 단계부터의 보안”을 도입합니다. HTTP 보안 헤더가 없으면 두 요건을 모두 충족하지 못합니다.

해결책: Caddy 헤더 설정

우리가 사용하는 리버스 프록시인 Caddy 덕분에 해결책은 모든 도메인에 적용할 수 있는 재사용 가능한 단일 header 블록이었습니다. 실제로 추가한 내용은 다음과 같습니다.

# 전역 헤더 스니펫 — 모든 프로덕션 사이트에 추가
(security_headers) {
  header {
    # HTTPS 강제 — NIS2 제21조 제2항 h호: 안전한 통신
    Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # XSS 및 삽입 공격 차단 — NIS2 제21조 제2항 d호: 공급망 보안
    Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://fonts.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'none'"

    # 클릭재킹 방지 — NIS2 제21조 제2항 b호
    X-Frame-Options "DENY"

    # MIME 스니핑 차단 — NIS2 제21조 제2항 b호
    X-Content-Type-Options "nosniff"

    # 리퍼러 정보 유출 제한 — NIS2 제21조 제2항 e호
    Referrer-Policy "strict-origin-when-cross-origin"

    # 브라우저 API 제한 — NIS2 제25조: 설계 단계부터의 보안
    Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()"

    # 서버 지문 정보 제거
    -Server
    -X-Powered-By
  } }

그런 다음 각 사이트 블록에서 이 스니펫을 불러왔습니다.

# brnz.ai
brnz.ai, www.brnz.ai {
  import security_headers
  reverse_proxy localhost:3001
}

# codeforceai.com
codeforceai.com, www.codeforceai.com {
  import security_headers
  reverse_proxy localhost:3002
}

Caddy를 다시 불러오고 브라우저 DevTools에서 헤더를 확인하면 끝입니다.

caddy reload --config /etc/caddy/Caddyfile

전체 과정: 시작부터 완료까지 30분

T+0:00
세 도메인 모두에서 KENSAI 검사 시작
자동 NIS2 규정 준수 평가가 대기열에 들어가 실행됐습니다.
T+0:04
검사 결과 확인 — 두 도메인이 B등급으로 표시됨
brnz.ai와 codeforceai.com은 각각 0.786점이었으며, 도메인마다 누락된 헤더 여섯 개가 확인됐습니다.
T+0:07
근본 원인 분석
kensai.app에는 이미 헤더 블록이 있었지만 brnz.ai와 codeforceai.com에는 전혀 없었습니다.
T+0:15
Caddy 설정 업데이트
(security_headers) 스니펫을 추가해 두 사이트 블록에서 불러오고 git에 커밋했습니다.
T+0:17
서비스 중단 없이 Caddy 다시 불러오기
caddy reload가 새 헤더를 즉시 적용했습니다. 재시작은 필요하지 않았습니다.
T+0:22
curl로 검증
HTTP 응답에 헤더 여섯 개가 모두 있는지 확인했으며 회귀는 발견되지 않았습니다.
T+0:29
재검사 완료 — A등급 확인
두 도메인 모두 점수가 0.997로 올랐습니다. NIS2 규정 준수가 복구됐고 사후 분석도 문서화했습니다.

수정 전과 후

⚠ 수정 전
B
점수: 0.786 / 1.000
  • HSTS 누락
  • CSP 누락
  • X-Frame-Options 누락
  • X-Content-Type-Options 누락
  • Referrer-Policy 누락
  • Permissions-Policy 누락
✓ 수정 후
A
점수: 0.997 / 1.000
  • preload가 적용된 HSTS
  • 삽입 공격을 차단하는 CSP
  • X-Frame-Options: DENY
  • X-Content-Type-Options: nosniff
  • Referrer-Policy: strict-origin
  • Permissions-Policy: 접근 제한
결과: brnz.ai와 codeforceai.com은 30분도 안 돼 B등급(0.786)에서 A등급(0.997)으로 올라갔습니다. 바꾼 것은 Caddy 설정에 HTTP 헤더 여섯 개를 추가한 것뿐입니다. 코드 변경도, 배포도, 서비스 중단도 없었습니다.

핵심 교훈

1. 보안 헤더는 선택 사항이 아니라 NIS2 규정 준수 항목입니다

NIS2 규제 대상 기관이라면 기본 HTTP 보안 헤더를 갖춰야 합니다. 규제기관은 감사 과정에서 자동 검사를 점점 더 많이 실행합니다. 누락된 Strict-Transport-Security 헤더는 사소한 실수가 아니라 제21조 제2항에 따른 위험 관리가 부족하다는 증거입니다.

2. 보안 기업에도 공백은 생깁니다

규정 준수 도구를 만드는 우리에게도 B등급 사이트가 두 곳 있었습니다. 부끄러운 일이 아니라 설정 드리프트가 발생한다는 사실을 일깨워 주는 사례입니다. 급히 연 도메인, 동기화되지 않은 Caddyfile, 누락된 import 하나가 원인이 될 수 있습니다. 자동 검사는 수동 감사가 놓치는 문제를 잡아냅니다.

3. 해결책은 거의 언제나 단순합니다

누락된 헤더 여섯 개, Caddy 설정 30줄, 작업 시간 30분이 전부였습니다. B등급과 A등급의 차이는 한 달짜리 프로젝트가 아니라 오후 한 번의 작업입니다. 어려운 점은 무엇보다 공백이 있다는 사실을 알아내는 것입니다.

4. 재사용 가능한 스니펫으로 향후 드리프트를 막을 수 있습니다

헤더를 (security_headers) 스니펫으로 분리하면 새 도메인을 추가할 때 단 하나의 import 줄만 포함해도 NIS2 헤더가 자동으로 모두 적용됩니다. 규정 준수가 뒤늦은 보완이 아니라 기본값이 됩니다.


이것이 귀사에 의미하는 바

NIS2 적용 대상이거나 감사를 준비하고 있다면 HTTP 보안 헤더는 규제기관이 가장 먼저 확인하는 항목 중 하나입니다. 빠르게 검사할 수 있고 평가 기준이 명확하며 수정도 간단합니다. 30분이면 A등급을 받을 수 있는데 B등급에 머물 이유가 없습니다.

검사를 실행하고 보고서를 읽으십시오. 표시된 문제를 고친 뒤 재검사로 확인하십시오.

NIS2 규정 준수 무료 확인

우리가 자체 도메인에 실행한 것과 같은 검사를 사용해 보십시오. NIS2 규정 준수 등급과 누락된 헤더를 정확히 확인하고 즉시 실행할 수 있는 개선 보고서를 받을 수 있습니다.

무료 NIS2 검사 시작 →

🛡️ 귀하의 웹사이트는 안전한가요?

공격자보다 먼저 취약점을 발견하세요.

웹사이트를 무료로 스캔하세요 →

관련 기사

3월 2일 보안 브리핑: 랜섬웨어 조직의 표적 2026년 3월 보안 규제 업데이트: NIS2 Cisco SD-WAN 관련 CISA 긴급 지침