CSP 생성기
사이트 리소스에 맞는 Content-Security-Policy 헤더를 생성합니다.
Content-Security-Policy(CSP)는 브라우저가 어떤 출처의 스크립트·스타일·이미지·폰트·연결을 허용할지 지정하는 보안 헤더입니다. 잘 설계된 CSP는 XSS(크로스 사이트 스크립팅)와 데이터 탈취, 클릭재킹 같은 공격의 영향을 크게 줄여 줍니다. 이 CSP 생성기는 default-src, script-src 등 주요 디렉티브별로 허용 소스를 체크박스로 고르고 커스텀 도메인을 추가하면, 그에 맞는 헤더 문자열을 실시간으로 조립해 줍니다.
만든 CSP는 응답 헤더(Content-Security-Policy)나 <meta> 태그로 적용할 수 있습니다. 처음에는 보고 전용(Content-Security-Policy-Report-Only)으로 배포해 위반 리포트를 모으며 정책을 다듬은 뒤 본격 적용하는 것을 권장합니다. 모든 계산은 브라우저 안에서만 일어나며 입력값은 어디에도 전송되지 않습니다.
허용할 디렉티브를 켜고, 소스 키워드를 고르거나 커스텀 도메인을 입력하세요.
default-src 'self'
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
주요 디렉티브 이해하기
CSP는 리소스 종류별로 허용 출처를 나눠 지정합니다. 가장 중요한 출발점은 default-src로, 개별 디렉티브가 지정되지 않은 리소스에 대한 기본 정책 역할을 합니다.
- default-src: 다른
*-src디렉티브가 없을 때 적용되는 기본 폴백. - script-src: 자바스크립트 실행 출처. 가장 보안에 민감합니다.
- style-src: CSS 스타일시트와 인라인 스타일 출처.
- img-src: 이미지 로드 출처.
- font-src: 웹폰트 출처.
- connect-src: fetch·XHR·WebSocket·EventSource 등 네트워크 연결 출처.
- frame-src: iframe으로 삽입할 수 있는 출처.
소스 키워드의 의미와 unsafe-inline의 위험
각 디렉티브에는 키워드와 도메인을 섞어 넣을 수 있습니다. 'self'는 같은 출처(scheme + host + port)를, 'none'은 모든 출처 차단을 의미합니다. data:는 인라인 데이터 URI를, https:는 임의의 HTTPS 출처를 허용합니다.
- 'unsafe-inline':
<script>인라인 코드나onclick같은 인라인 핸들러, 인라인<style>을 허용합니다. 이 키워드를script-src에 켜면 CSP의 XSS 방어 효과가 사실상 사라지므로 가급적 쓰지 말고, nonce나 hash 방식으로 대체하세요. - https:나 와일드카드(
*)처럼 지나치게 넓은 출처는 신뢰할 수 없는 제3자 리소스까지 허용할 수 있으니, 실제로 쓰는 CDN·API 도메인으로 좁히는 편이 안전합니다. - 'none'은 단독으로만 의미가 있습니다. 다른 출처와 함께 쓰면 효과가 없습니다.
적용과 점진적 도입
- 먼저
Content-Security-Policy-Report-Only헤더로 배포해 위반 리포트를 수집합니다. - 리포트를 보며 정상 동작에 필요한 출처를 디렉티브에 추가해 정책을 다듬습니다.
- 위반이 사라지면 본 헤더(
Content-Security-Policy)로 전환해 실제 차단을 활성화합니다.
XSS 방어를 강화하려면 script-src에서 'unsafe-inline'을 빼고 nonce·hash 기반으로 운영하는 것이 모범 사례입니다. 적용을 마쳤다면 보안 헤더 점검으로 CSP가 응답에 실제로 내려가고 있는지 확인하세요.
소스 표현식 빠른 참조
디렉티브 값에 자주 들어가는 소스 표현식과 그 의미를 정리했습니다. 'nonce-...'·'sha256-...'·'strict-dynamic'은 작은따옴표가 헤더 문자열에 그대로 포함되어야 합니다(예: script-src 'nonce-r4nd0m').
| 소스 표현식 | 허용 대상 | 메모 |
|---|---|---|
'self' | 같은 출처(scheme+host+port) | 서브도메인은 미포함. cdn.example.com은 별도로 추가해야 함 |
'none' | 전부 차단 | 단독일 때만 유효 |
'unsafe-inline' | 인라인 스크립트/스타일·인라인 핸들러 | nonce/hash가 함께 있으면 최신 브라우저가 무시함 |
'unsafe-eval' | eval()·new Function()·문자열 setTimeout | 일부 구형 라이브러리·템플릿 엔진이 요구 |
'nonce-...' | 같은 nonce를 가진 인라인 태그 | 요청마다 새로 생성된 무작위 값이어야 함 |
'sha256-...' | 해시가 일치하는 인라인 코드 | 코드 한 글자만 바뀌어도 해시 재계산 필요 |
'strict-dynamic' | nonce/hash로 신뢰된 스크립트가 동적으로 부른 스크립트 | 켜면 호스트·https: 화이트리스트가 무시됨 |
data: | data URI | img-src엔 흔하지만 script-src엔 위험 |
frame-ancestors와 frame-src는 다릅니다
이름이 비슷해 헷갈리지만 방향이 반대입니다. frame-src는 내 페이지가 어떤 출처를 iframe으로 품을 수 있는가를, frame-ancestors는 어떤 출처가 내 페이지를 iframe으로 품을 수 있는가(클릭재킹 방어, X-Frame-Options 대체)를 제어합니다. 클릭재킹을 막으려면frame-ancestors 'self' 또는 frame-ancestors 'none'을 쓰세요. 단,frame-ancestors는 <meta> 태그에서는 동작하지 않으므로 반드시 응답 헤더로 내려야 합니다.
예시로 읽어 보기
Google Fonts와 자체 API를 쓰는 SPA에 적용할 만한 정책을 가정해 보겠습니다.
default-src 'self'; script-src 'self' 'nonce-AbC123'; style-src 'self' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self' https://api.example.com; frame-ancestors 'none'
- 인라인 부트스트랩 스크립트는
<script nonce="AbC123">처럼 같은 nonce를 달아야만 실행됩니다. - Google Fonts의 CSS는
fonts.googleapis.com, 실제 폰트 파일은fonts.gstatic.com으로 출처가 나뉘므로 둘 다 필요합니다. - 아이콘을 base64로 인라인하므로
img-src에data:를 허용했습니다. connect-src에 자체 API만 넣어 다른 도메인으로의 fetch·XHR 유출을 막습니다.frame-ancestors 'none'으로 외부 사이트의 iframe 삽입(클릭재킹)을 차단합니다.
흔한 실수 / 함정
'self'가 서브도메인까지 덮는다고 오해하기 쉽습니다.example.com에서 내려준 CSP의'self'는cdn.example.com을 포함하지 않으므로 서브도메인은 명시적으로 추가해야 합니다.- nonce/hash와
'unsafe-inline'을 같이 넣으면 안전해진다고 생각하는 경우가 있는데, CSP3 브라우저는 nonce/hash가 있으면'unsafe-inline'을 무시합니다(구형 브라우저 폴백 용도로만 의미). 반대로 nonce를 페이지마다 고정값으로 재사용하면 보호 효과가 사라집니다 — 요청마다 새로 생성해야 합니다.
자주 묻는 질문
default-src만 지정하면 충분한가요?
unsafe-inline은 절대 쓰면 안 되나요?
생성한 CSP는 어디에 넣나요?
정책이 너무 엄격해서 사이트가 깨지면 어떻게 하나요?
입력한 도메인이 서버로 전송되나요?
관련 가이드
- 필수 보안 헤더 설정 가이드(CSP·HSTS·X-Frame-Options)꼭 설정해야 할 보안 헤더와 각 헤더의 역할·권장 값·흔한 실수.