KENSAI로 자체 웹사이트를 검사한 결과 중대한 NIS2 규정 준수 공백을 발견했습니다. HTTP 보안 헤더가 누락돼 세 도메인 중 두 곳의 등급이 B(0.786)로 떨어져 있었습니다. 무엇이 잘못됐고, NIS2의 어느 조항이 위험했으며, Caddy 설정을 30분 수정해 어떻게 모두 해결했는지 자세히 설명합니다.
우리는 보안 검사 플랫폼을 만들고 고객에게 NIS2 규정 준수를 강조합니다. 그런데 자체 도메인에 KENSAI를 실행해 보니 세 곳 중 두 곳이 규정을 충족하지 못하고 있었습니다.
취약점도 침해도 없었습니다. 단지 HTTP 보안 헤더가 빠져 있었습니다. 규제기관이 먼저 확인하고 공격자가 그다음 노리는, 눈에 띄지 않는 공백입니다. NIS2 지침 제21조 제2항에 따라 규제 대상 기관에 이 헤더는 선택 사항이 아니라 기본 보안 위생 요건입니다.
무엇을 발견했고 얼마나 빨리 고쳤는지 살펴보겠습니다.
2026년 3월 15일, 포트폴리오의 세 도메인 모두에 KENSAI 자동 NIS2 규정 준수 검사를 실행했습니다.
kensai.app 점수는 올바른 Caddy 헤더 설정이 이미 적용돼 0.997로 거의 만점에 가까웠습니다. 나머지 두 도메인인 brnz.ai 및 codeforceai.com 두 곳은 모두 0.786점이었고, 동일한 핵심 보안 헤더 여섯 개가 빠져 있었습니다.
문제가 있던 두 도메인 모두 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조 — 설계 단계부터의 보안 | ✗ 누락 |
우리가 사용하는 리버스 프록시인 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
NIS2 규제 대상 기관이라면 기본 HTTP 보안 헤더를 갖춰야 합니다. 규제기관은 감사 과정에서 자동 검사를 점점 더 많이 실행합니다. 누락된 Strict-Transport-Security 헤더는 사소한 실수가 아니라 제21조 제2항에 따른 위험 관리가 부족하다는 증거입니다.
규정 준수 도구를 만드는 우리에게도 B등급 사이트가 두 곳 있었습니다. 부끄러운 일이 아니라 설정 드리프트가 발생한다는 사실을 일깨워 주는 사례입니다. 급히 연 도메인, 동기화되지 않은 Caddyfile, 누락된 import 하나가 원인이 될 수 있습니다. 자동 검사는 수동 감사가 놓치는 문제를 잡아냅니다.
누락된 헤더 여섯 개, Caddy 설정 30줄, 작업 시간 30분이 전부였습니다. B등급과 A등급의 차이는 한 달짜리 프로젝트가 아니라 오후 한 번의 작업입니다. 어려운 점은 무엇보다 공백이 있다는 사실을 알아내는 것입니다.
헤더를 (security_headers) 스니펫으로 분리하면 새 도메인을 추가할 때 단 하나의 import 줄만 포함해도 NIS2 헤더가 자동으로 모두 적용됩니다. 규정 준수가 뒤늦은 보완이 아니라 기본값이 됩니다.
NIS2 적용 대상이거나 감사를 준비하고 있다면 HTTP 보안 헤더는 규제기관이 가장 먼저 확인하는 항목 중 하나입니다. 빠르게 검사할 수 있고 평가 기준이 명확하며 수정도 간단합니다. 30분이면 A등급을 받을 수 있는데 B등급에 머물 이유가 없습니다.
검사를 실행하고 보고서를 읽으십시오. 표시된 문제를 고친 뒤 재검사로 확인하십시오.
우리가 자체 도메인에 실행한 것과 같은 검사를 사용해 보십시오. NIS2 규정 준수 등급과 누락된 헤더를 정확히 확인하고 즉시 실행할 수 있는 개선 보고서를 받을 수 있습니다.
무료 NIS2 검사 시작 →