Conceptly
← 전체 목록
🧱

Content Security Policy

보안페이지에서 로드할 수 있는 리소스를 제한하는 보안 정책

CSP(Content Security Policy)는 웹 페이지가 로드할 수 있는 리소스의 출처와 유형을 서버가 HTTP 헤더로 명시하여, 브라우저가 그 범위 밖의 스크립트·스타일·이미지 등을 차단하게 하는 보안 메커니즘입니다. XSS(교차 사이트 스크립팅) 공격의 피해를 줄이는 가장 강력한 방어 수단 중 하나입니다.

아키텍처 다이어그램

🔗 관계 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

웹 애플리케이션에서 사용자 입력을 받아 페이지에 표시하는 기능은 어디에나 있습니다. 댓글, 프로필, 검색어, 게시글 제목. 이 입력값에 <script> 태그가 섞여 들어가면 브라우저는 그것이 개발자가 의도한 코드인지, 공격자가 삽입한 코드인지 구분하지 못합니다. 이것이 XSS(Cross-Site Scripting) 공격입니다. 서버 측에서 입력값을 이스케이프(escape)하거나 필터링하는 것이 1차 방어선이지만, 수백 개의 입력 경로 중 하나라도 놓치면 뚫립니다. 새 기능이 추가될 때마다 모든 경로를 빠짐없이 검증하기란 현실적으로 어렵습니다. CSP는 이 문제에 대한 접근을 뒤집습니다. 입력을 완벽하게 필터링하는 대신, 브라우저에게 '이 페이지에서 실행 가능한 스크립트는 여기서 온 것뿐이다'라고 알려주는 것입니다. 서버 측 필터를 뚫고 스크립트가 삽입되더라도 CSP 정책에 포함되지 않은 코드는 브라우저가 실행하지 않습니다.

왜 이런 방식이 등장했나요?

XSS는 2000년대 초반부터 가장 흔한 웹 취약점 중 하나로 꾸준히 보고되어 왔습니다. 서버 측 필터링, 출력 인코딩, 프레임워크 수준의 자동 이스케이프 같은 방어 기법이 발전했지만, 웹 애플리케이션이 복잡해지면서 모든 입력 경로를 빠짐없이 막는 것은 점점 더 어려워졌습니다. 서드파티 스크립트, 광고 네트워크, 분석 도구, 사용자 생성 콘텐츠가 늘어나면서 페이지 안에서 실행되는 코드의 출처도 다양해졌습니다. 이런 환경에서 '허용된 코드만 실행되게 한다'는 발상이 나왔고, 2012년 W3C가 CSP 1.0을 권고안으로 발표했습니다. 서버가 응답 헤더에 정책을 넣으면 브라우저가 그 규칙을 시행하는 구조는, 개발자가 모든 공격을 예측하지 못하더라도 피해 범위를 제한할 수 있게 만들었습니다. CSP 2.0에서 nonce와 hash 지원이 추가되면서 인라인 스크립트가 필요한 현실적인 상황도 다룰 수 있게 됐습니다.

안에서 어떻게 동작하나요?

CSP는 서버가 HTTP 응답 헤더인 Content-Security-Policy에 정책을 담아 보내는 것으로 시작합니다. 브라우저는 이 정책을 파싱한 뒤, 페이지가 리소스를 로드하거나 스크립트를 실행할 때마다 해당 정책에 맞는지 검사합니다. 정책은 디렉티브(directive)와 소스 리스트(source list)로 구성됩니다. script-src 'self' https://cdn.example.com이라고 쓰면, 스크립트는 같은 출처('self')와 cdn.example.com에서만 로드할 수 있다는 뜻입니다. 이 목록에 없는 출처의 스크립트는 브라우저가 로드 자체를 거부합니다. style-src, img-src, connect-src 등 리소스 유형별로 각각 다른 정책을 설정할 수 있고, default-src는 별도 지정이 없는 유형의 기본 정책이 됩니다. 인라인 스크립트는 기본적으로 차단됩니다. 이것이 CSP의 핵심 방어력입니다. 공격자가 XSS로 삽입하는 코드는 대부분 인라인이기 때문입니다. 그런데 레거시 코드나 분석 도구 때문에 인라인 스크립트가 불가피한 경우, 서버가 각 응답마다 일회성 nonce 값을 생성하고 script 태그에 동일한 nonce를 붙이면, 그 특정 스크립트만 허용할 수 있습니다. 이렇게 하면 공격자가 삽입한 스크립트에는 올바른 nonce가 없으므로 여전히 차단됩니다. Report-Only 모드로 Content-Security-Policy-Report-Only 헤더를 사용하면, 위반을 차단하지 않고 보고만 합니다. 기존 사이트에 CSP를 처음 도입할 때 어떤 리소스가 차단될지 파악하는 용도로 매우 유용합니다.

무엇과 헷갈리나요?

CSP와 CORS는 둘 다 브라우저가 시행하는 보안 정책이지만 제어하는 대상이 다릅니다. CSP는 '이 페이지 안에서 어떤 출처의 리소스를 로드하고 실행할 수 있는가'를 정합니다. 서버가 자기 페이지에서 허용할 범위를 선언하는 것입니다. CORS는 '다른 출처의 서버에 자바스크립트로 요청을 보냈을 때 그 서버가 응답을 허용하는가'를 다룹니다. 요청받는 쪽 서버가 허용 여부를 결정하는 것입니다. 한 가지 더 구분해야 할 것은 CSP와 서버 측 입력 검증의 관계입니다. CSP가 있으면 입력 검증을 안 해도 된다고 생각할 수 있지만, CSP는 실행을 차단하는 최후의 방어선이지 입력 자체를 정제하는 것은 아닙니다. 서버 측 필터링이 1차 방어이고 CSP는 그 필터를 뚫고 들어온 코드까지 잡는 2차 방어선입니다. 둘 다 있어야 방어가 두텁습니다.

언제 쓰나요?

CSP를 기존 서비스에 처음 적용할 때 가장 현실적인 접근은 Report-Only 모드부터 시작하는 것입니다. Content-Security-Policy-Report-Only 헤더와 report-uri 디렉티브를 설정하면, 차단 없이 위반 내역이 지정된 엔드포인트로 수집됩니다. 이 데이터를 보고 어떤 인라인 스크립트, 어떤 서드파티 출처가 실제로 쓰이는지 파악한 뒤에 정책을 확정하면 사이트가 갑자기 깨지는 사고를 막을 수 있습니다. 인라인 스크립트를 전면 금지하는 것이 이상적이지만, Google Analytics나 마케팅 태그 같은 서드파티 코드가 인라인을 요구하는 경우가 많습니다. 이때 unsafe-inline을 쓰면 CSP의 방어력이 크게 줄어들므로, nonce를 사용하는 편이 낫습니다. 서버가 매 응답마다 고유한 nonce를 생성하고, 허용할 스크립트 태그에만 그 nonce를 넣으면 됩니다. CSP 위반 보고를 모니터링하면 XSS 시도를 감지하는 부수적 효과도 있습니다. 정상 운영 중에 갑자기 위반 보고가 급증하면 공격 시도이거나, 의도하지 않은 서드파티 스크립트 변경일 수 있습니다.

XSS 방어데이터 유출 방지혼합 콘텐츠 차단서드파티 스크립트 통제