2 min read
CSP 운영 하드닝 가이드
Report-Only에서 Enforce 전환까지 단계적으로 진행하는 CSP 정책 정착 방법

도입
CSP는 보안 헤더 한 줄로 끝나는 설정이 아니다. 운영 환경에서는 서드파티 스크립트, 인라인 스타일, 프레임 임베딩 요구가 충돌하기 때문에 단계적 하드닝이 필요하다. 이 글은 Report-Only에서 Enforcement까지 전환하는 실무 절차를 안내한다.

문제 정의
CSP를 급하게 적용하면 정상 기능이 깨지거나, 반대로 너무 느슨한 정책으로 무력화되는 문제가 발생한다.
- nonce/hash 전략 없이
unsafe-inline을 남겨 실효성이 없다. - 외부 도메인 화이트리스트가 방치되어 보안 표면이 계속 확대된다.
- 위반 리포트를 수집하지 않아 실제 차단 영향 범위를 알 수 없다.
정답은 한 번에 엄격하게 막는 것이 아니라 계측 후 수렴이다. Report-Only 모드에서 위반 패턴을 수집하고 정책을 좁혀야 한다.
핵심 개념
| 관점 | 설계 기준 | 검증 포인트 |
|---|---|---|
| 도입 단계 | Report-Only 시작 | 위반 이벤트 유형 |
| 정책 축소 | 도메인 화이트리스트 최소화 | 불필요 허용 항목 수 |
| 스크립트 제어 | nonce/hash 적용 | inline script 차단률 |
| 운영 | 위반 리포트 모니터링 | 정책 변경 리드타임 |
CSP는 보안팀 단독 과제가 아니다. 프론트엔드와 마케팅 스크립트 운영 담당자가 함께 정책 소유자가 되어야 지속 가능하다.
코드 예시 1: CSP 헤더 생성
export function buildCspHeader(nonce: string) {
return [
"default-src 'self'",
"script-src 'self' 'nonce-" + nonce + "' https://www.googletagmanager.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"connect-src 'self' https://www.google-analytics.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"object-src 'none'",
].join("; ");
}
코드 예시 2: Next.js middleware 적용
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(req: NextRequest) {
const nonce = crypto.randomUUID().replace(/-/g, "");
const res = NextResponse.next();
res.headers.set("Content-Security-Policy-Report-Only", buildCspHeader(nonce));
res.headers.set("Report-To", '{"group":"csp","max_age":10886400,"endpoints":[{"url":"https://csp.8space.dev/report"}]}');
return res;
}
아키텍처 흐름
Mermaid diagram rendering...
트레이드오프
- 엄격한 정책은 보안을 높이지만 서드파티 스크립트 유지 비용이 증가한다.
- Report-Only 기간을 길게 두면 안정적이지만 실제 차단 전환이 늦어질 수 있다.
- nonce 전략은 안전하지만 SSR/캐시 아키텍처와의 정합성을 추가로 고려해야 한다.
정리
CSP 하드닝은 점진적 수렴 과정이다. 위반 리포트를 기반으로 정책을 축소하고 최종 Enforcement로 전환하면, 서비스 가용성을 해치지 않으면서 보안 강도를 높일 수 있다.
이미지 출처
- Cover: source link
- License: OGL v1.0 / Author: Harland Quarrington
- Note: Wikimedia Commons 무료 라이선스 이미지를 다운로드 후 1600px 기준 JPG로 최적화했습니다.