신뢰하는 도메인에 업로드

만약 정책에서 허용하는 출처가 파일 업로드 및 다운로드 기능을 제공한다면, 공격자는 출처에 스크립트와 같은 자원을 업로드한 뒤, 다운로드 경로로 웹 페이지 자원을 포함시킬 수 있다.

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
...
<h1>검색 결과: <script src="/download_file.php?id=177742"></script></h1>

외부 자원 업로드 예시

 

 

 

JSONP API

만약 CSP에서 허용한 출처가 JSONP API를 지원한다면, callback 파라미터에 원하는 스크립트를 삽입하여 공격이 가능함

(JSONP - 웹 애플리케이션에서 서로 다른 도메인 간에 데이터를 주고받을 때 사용되는 기술)

 

웹 페이지에서 *.google.com 에서 온 출처만 허용한다고 가정하면, 구글에서  JSOMP API를 지원하는 서버를 찾아 callback에 원하는 스크립트를 삽입할 수 있다.

https://accounts.google.com/o/oauth2/revoke?callback=alert(1);

 

JSONP API를 제공하는 서비스는 콜백 이름에 식별자를 제외한 문자를 거부함으로써 이를 추가적으로 방어할 수 있다.

그러나 가능한 경우 JSONP보다는 CORS를 지원하는 API를 사용하는 것이 좋다.

 

 

 

nonce 예측 가능

CSP의 nonce는 예측 불가능한 값을 태그 속성에 포함시켜 XSS 공격을 방어하는 데 사용된다.

이 방어를 효과적으로 구현하려면 몇 가지 주의사항이 필요하다.

  • nonce 의 예측 불가능성: nonce 값은 요청마다 새로 생성되며, 공격자가 예측하거나 취득할 수 없는 값이어야 한다. nonce 생성 알고리즘이 취약하면 공격자가 이를 예측해 악성 스크립트를 삽입할 수 있다.
  • 캐싱 주의: nonce가 포함된 HTTP 헤더나 <meta> 태그가 캐싱되지 않도록 해야 한다. 특히, PHP나 CGI와 같은 서버 스크립트는 경로에 따라 잘못된 캐싱이 발생할 수 있다. 예를 들어, '.css' 확장자 파일이 캐시되어 같은 nonce 값이 반환되면, 공격자가 이를 악용할 수 있다.
  • 보안 난수 생성기 사용: nonce 값은 보안상 안전한 의사 난수 생성기를 사용해 생성해야 한다. 공격자가 예측할 수 있는 현재 시각 기반의 난수 생성기 (srand(), rand()) 는 사용하지 말아야 한다.

 

 

Nginx와 PHP FastCGI SAPI(php-fpm) 설정에서는 nonce의 캐싱으로 인한 보안 취약점이 발생할 수 있다.

location ~ \.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}

 

 

  • 현재 문제점:
    • /dom_xss_vulnerable.php/style.css와 같은 경로로 접근할 때, PHP 파일이 실행되어 nonce가 <meta> 태그로 출력됩니다.
    • CDN은 일반적으로 CSS나 스크립트 같은 정적 파일을 캐싱하므로, 출력된 nonce도 캐싱됩니다.
    • 공격자는 고정된 nonce 값을 이용해 XSS 공격이 가능: <script nonce="{고정된 nonce 값}">alert(1);</script>
  • 기존 fastcgi-php.conf 설정:
    • $fastcgi_split_path_info를 사용하여 .php 경로 뒤에 추가 경로를 허용 (fastcgi_split_path_info ^(.+\.php)(/.+)$;).
    • 이러한 설정은 PHP가 경로 뒤의 CSS 파일처럼 보이는 요청도 실행하게 만듭니다.
  • 수정 방법:
    • PATH_INFO 기능을 사용하지 않는 경우: .php로 끝나는 URL만 FastCGI로 전달되도록 수정해야함
location ~ \.php$ {
    try_files $uri =404;
    fastcgi_index index.php;
    include fastcgi.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}

 

 

 

 

base-uri 미지정

HTML의 하이퍼링크에서 경로를 지정할 때, 호스트 주소 없이 경로를 사용하면 브라우저는 현재 문서를 기준으로 경로를 해석한다.

<base> 태그는 이 기준점을 변경하여 <a>, <from> 등의 기본 target 속성을 지정할 수 있다.

 

공격 시나리오

  • 공격자가 <base href f="https://malice.test/xss-proxy/">와 같은 마크업을 삽입하면, 이후 모든 상대 경로가 공격자의 서버를 가리키게 되어 임의의 스크립트가 삽입될 수 있다.

방어 방법

  • CSP base-uri 지시문을 사용하여 <base> 태그의 href 속성을 제한한다.
Content-Security-Policy: base-uri 'none'

 

Nonce Retargeting 공격

  • CSP가 스크립트 실행을 막더라도, base-uri 지시문이 설정되지 않은 경우 <base> 태그를 이용해 공격자가 임의의 자원을 로드할 수 있다.
<base href="https://malice.test">
<script src="/jquery.js" nonce=NONCE>
//jquery.js는 https://malice.test/jquery.js를 가리키게 된다

 

 

 

 

Content Security Policy (CSP)

  • 웹 보안을 강화하기 위해 웹 브라우저가 웹사이트의 리소스를 로드하는 방식을 제어하는 웹 보안 표준
  • 웹 사이트가 신뢰할 수 있는 리소스 출처를 명시적으로 지정함으로써, XSS(Cross-Site Scripting), 데이터 삽입 공격 등과 같은 일반적인 웹 공격을 방지
  • XSS 공격으로부터 피해를 최소화할 수 있는 방안이지만, XSS 공격의 피해를 완전히 무력화하기 위한 수단은 아님

 

사용 방법

CSP는 HTTP 헤더HTML의 <meta> 태그를 통해 정의됨

CSP 구문은 여러 정책 지시문(policy-directive)으로 구성되며, 각 지시문은 세미콜론(;)으로 구분됨

 

 

CSP 적용 예시

페이지 자원이 동일 오리진('self') 또는 특정 도메인(https://example.dreamhack.io)에서만 로드되도록 설정하는 예시

  • HTTP 헤더 사용
Content-Security-Policy: default-src 'self' https://example.dreamhack.io

 

  • HTML <meta> 태그 사용
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://example.dreamhack.io">

 

 

 

 

CSP는 웹 페이지 보안을 위해 인라인 코드와 문자열을 실행하는 메커니즘을 기본적으로 차단한다.

 

CSP 기본 정책 - 인라인 코드 (Inline Code)

  • 인라인 코드 차단: <script>alert(1);</script>와 같이 <script> 태그 안에 직접 코드를 삽입하는 인라인 코드를 유해하다고 간주하여 사용을 차단
  • 외부 스크립트 권장: 인라인 코드 대신 <script src="alert.js"></script> 처럼 scr 속성을 사용해 외부 스크립트를 로드하도록 권장
  • 허용되지 않는 인라인 코드 유형:
    • on 이벤트 핸들러 속성 (예: onclick="...")
    • javascript: URL 스킴
    • 인라인 <style> 태그와 style 속성도 차단되며, 외부 스타일시트 사용을 권장

CSP 기본 정책 - eval

  • eval 차단: eval() 함수과 같이 문자열을 실행 가능항 자바스크립트 고드로 변환하는 모든 메커니즘을 차단
  • 차단되는 예제: setTimeout("alert(1)", ....) 와 같이 문자열을 사용한 함수 호출은 차단
  • 허용되는 예제: setTimeout(function(){alert(1)}, ...) 처럼 인라인 함수 형태로 전달되는 경우는 허용

 

Policy Directive

  • <directive> <value> 형식으로 구성됨
    • <directive> (지시문): 어떤 종류의 리소스에 대해 출처를 제어할지 결정하는 역할
    • <value> (값): 지시문에서 제어할 리소스의 출처를 정의하며, 여러 출처를 공백으로 구분하여 나열 가능
지시문 설명
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 페이지의 현재 출처 (Same Origin) 내에서 로드하는 리소스만 허용합니다.
unsafe-inline 예외적으로 인라인 코드의 사용을 허용합니다.
unsafe-eval 예외적으로 eval 과 같은 텍스트-자바스크립트 변환 메커니즘의 사용을 허용합니다
nonce-<base64-value> nonce 속성을 설정하여 예외적으로 인라인 코드를 사용합니다. <base64-value>는 반드시 요청마다 다른 난수 값으로 설정해야 합니다. 해당 출처를 설정하면 unsafe-inline 은 무시됩니다.
<hash-algorithm>-<base64-value> script 혹은 style 태그 내 코드의 해시를 표현합니다. 해당 출처를 설정하면 unsafe-inline은 무시됩니다.

 

 

 

 

CSP Examples

Content-Security-Policy: default-src 'self'

모든 리소스의 출처를 현재 페이지와 같은 출처로 제한함

 

Content-Security-Policy: default-src 'self' https://googleapis.com https://*.googleapis.com

모든 리소스의 출처를 현재 페이지와 같은 출처와 " https://googleapis.com", "https://*.googleapis.com"으로 제한함 

 

Content-Security-Policy: default-src 'self'; img-src *; script-src static.dreamhack.io

모든 리소스의 출처를 현재 페이지와 같은 출처로 제한하고, 이미지의 출처는 모든 호스트를 허용, 스크립트 태그의 출처는 "static.dreamhack.io"로 제한

 

Content-Security-Policy: child-src 'self' frame.dreamhack.io

페이지 내에 삽입된 프레임 콘텐츠 URL은 현재 페이지와 같은 출처와 "frame.dreamhack.io"내의 컨텐츠만 로드할 수 있음

 

Content-Security-Policy: base-uri 'none'

base 태그의 URL은 어느 것도 허용하지 않음

 

Content-Security-Policy: script-src 'unsafe-eval'

자바스트립트 코드 내에 eval 과 같은 텍스트-자바스크립트 변환 메커니즘의 사용을 허용

 

Content-Security-Policy: script-src 'sha256-5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA='

스트립트 태그 내의 코드 혹은 src 속성으로 지정된 파일의 sha256 해시를 base64로 인코딩한 결과가 "5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA="와 다르다면 스크립트 로드에 실패

 

 

 

 

 

+ Recent posts