Study

CSP

cloudnaaam 2025. 6. 24. 11:18

- 이 글은 아직 현업을 경험하지 못한 보안 공부생의 정리 글이니, 정확하지 않을 수도 있습니다.-

 

CTF 풀 때 CSP를 포함한 문제가 나왔었다. 

중간에 계속 헷갈렸었으니 다시 한번 정리해보는 시간을 가져보도록 해보자.

 

CSP란?

Contents Security Policy. 콘텐츠 보안 정책이라고 한다.

주요 목표는 XSS 공격을 완화하고 보고하는 것이다. 브라우저는 콘텐츠의 출처를 신뢰하기 때문에 공격자가 주입한 악성 스크립트를 실행한다. 때문에 XSS 공격이 발생하는 것이고.

하지만 CSP를 통해서 신뢰할 수 있는 출처나 소스를 지정하면 XSS 공격을 완화할 수 있게 되는 것.

 

사용 방법은 두 가지가 있는데,

 

HTTP 헤더

Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com; style-src 'self' https://fonts.googleapis.com; img-src 'self' data: https://*.example.com;

 

HTML Meta 태그

<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-eval' 'unsafe-inline' https:; img-src 'self' data: blob: https:; font-src 'self' data: https:;">

 

이처럼 HTTP 헤더에 넣거나 Meta 태그에 포함시켜서 CSP를 적용시킬 수 있다.

 

또한 다양한 지시어가 존재하는데,

default-src 기본적으로 허용되는 리소스 출처를 지정한다.
script-src 스크립트의 출처를 지정한다. 
style-src 스타일 시트의 출처를 지정한다.
img-src 이미지의 출처를 지정한다.
media-src 오디오, 비디오와 같은 미디어 파일의 출처를 지정한다.
connect-src fetch, XMLHttpRequest, Navigator.sendBeacon, WebSocket 등의 HTTP 연결 요청의 출처를 제한한다.
frame-src iframe의 출처를 지정한다.
object-src object의 출처를 지정한다.
report-uri CSP 위반이 발생했을 경우 보고할 URL를 지정한다.
plugin-types 허용할 플러그인의 MIME 타입을 지정한다.
reflected-xss Reflected XSS 공격을 방지하기 위한 정책 지정. 

등이 있다.

 

이에 매치되는 값들은

self 현재 페이지의 도메인만 허용한다.
none 모든 리소스나 스타일을 차단한다.
unsafe-inline 인라인 스타일이나 스크립트를 허용한다. -- 취약할 수 있음
unsafe-eval eval() 함수를 사용하여 실행되는 스크립트를 허용한다. -- 취약함
nonce-<value> nonce 값을 사용하는 스크립트 허용.  보통 nonce값은 예측 불가능하고 계속 바뀌게 설계한다.
hash-<value> hash 값을 사용하는 스크립트 허용. 보통 sha-256 사용한다.
strict-dynamic 신뢰된 스크립트가 로드하는 스크립트도 허용. 단, nonce나 hash를 사용할 때만 사용 가능.

등이 있다.

 

사용 예시를 들어보면

Content-Security-Policy: script-src 'nonce-랜덤값' 'strict-dynamic'; object-src 'none'; base-uri 'none';

 

--> <script nonce='nonce 값'> 이런 식으로 설정된 스크립트와 이 놈이 불러오는 스크립트만 허용

이런 식으로 작동하는 것.

 

Bypass 하는 방법은 여러 가지가 있다.

 

와일드 카드를 잘못 썼을 경우, 그러니까

Content-Security-Policy: script-src 'self' http://safesite data: http://*

이런 경우에는

<script src="data:text/javascript;base64,...">

이런 식으로 페이로드 짜면 바로 실행된다. 신뢰 리소스가 http:// 포함한 모든 도메인으로 설정되어 있기 때문에..

 

혹은 nonce값을 충분히 랜덤한 값으로 설정하지 않는 경우 등이 있는데,

 

이번 MaltaCTF 롸업 보니까 특이한 케이스도 있더라.

 

'Content-Security-Policy', "script-src 'sha256-1ltlTOtatSNq5nY+DSYtbldahmQSfsXkeBYmBH5i9dQ=' 'strict-dynamic'; object-src 'none'

CSP는 이렇게 되어 있어서, 초기 신뢰 스크립트 중 스크립트 내용을 해시화한 값이 명시한 값과 같은 스크립트 및 해당 스크립트가 로드한 스크립트 까지만 실행이 가능하다.

 

여기서 초기 신뢰 스크립트 중 pace.js를 가져오는 스크립트가 존재했는데,

pace.js는 웹 페이지의 로딩 상황을 렌더링해주는 라이브러리인데, 내부에 객체 병합 코드가 존재한다.

defaultOptions  window.paceOptions data-pace-options 이 DOM 내부 요소를 병합하는 과정에서 prototype pollution을 통해 취약점이 발생할 수 있다.

 

때문에 초기에 로드하는 라이브러리 내부의 취약점을 통해서도 CSP를 bypass 할 수도 있다는 것도 알아두면 좋을 것 같다.

 

 

Reference

https://velog.io/@gth1123/meta%ED%83%9C%EA%B7%B8-Content-Security-Policy

https://hg2lee.tistory.com/entry/Content-Security-PolicyCSP-Bypass#JSONP%20Callback-1-12

https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CSP

https://github.com/CodeByZach/pace/issues/546

 

'Study' 카테고리의 다른 글

JWT (Json web token)  (0) 2025.08.20
Web cache deception  (0) 2025.07.19
pugjs 취약점  (0) 2025.06.26
Unicode case mapping collision  (0) 2025.06.26
Prototype Pollution  (0) 2025.06.25