Dyrandy

SOP, CORS, CSP 개념과 우회방법(Concept & Bypass) 본문

Concept Study/Web

SOP, CORS, CSP 개념과 우회방법(Concept & Bypass)

Dyrandy 2020. 3. 2. 20:10

Security Policy (SOP, CORS, CSP)

  • Dyrandy

Same-Origin Policy (SOP)

What is SOP (Same Origin Policy)?

한국말로는 일명 '동일 기원 정책' 혹은 '동일 출처 정책'이다. SOP는 간단히 말하자면 다른 기원에서 온 자원을 제한하는 정책이다. 현대 브라우저에서 지원하는 하나의 기능으로서 Javascript, Documents, Media, 등을 하나의 Origin에서 다른 Origin으로 통신을 하지 못하게 막는 정책이다. 이를 막고 있는 이유는 보안상의 이슈로 CSRF같은 요청이 난무 하지 않도록 하기 위해서다. (CST같은 취약점도 막는다)

좀 더 쉽게 표현하자면. 브라우저에서 동작하는 한 프로그램은 자기 자신과 같은 Origin으로 부터만 리소스에 접근 할 수 있다는 것이다.

왜 SOP가 필요하며, Same-Origin이라는 것은 뭘까?

Why do we need SOP?

SOP가 없다면 어떻게 될까?

만약 A라는 유저가 속아 google.ca가 아닌 gooogle.ca에 접속했다고 생각해보자. 그리고 이 A라는 유저는 의심없이 google.ca에 로그인을 하거나 같은 브라우저에서 google.ca에 로그인 중이라면, gooogle.ca에서 AJAX같은 요청으로 비밀리에 google.ca에 요청을 보내고 어떠한 기능들을 수행하게 하거나, 정보를 탈취 할 수 있다(Cross Site Request Forgery, CSRF).

바로 이런 문제들 때문에 SOP가 적용 된 것이다. 그러면 Same-Origin은 과연 무엇이며, 어디까지 Same-Origin이라고 봐야할까?

Same-Origin?

웹에서 말하는 Same-Origin이란, 같은 프로토콜, 호스트, 포트를 사용하는 Origin들을 말한다. 것을 말한다. 다음 예시들을 보자

http://www.example.com/dir1/dir2.html 이 있다고 가정해보자. 이 URL과 Same-Origin인 URL들과 Same-Origin인 이유를 살펴보자.

비교대상 URL Status Reason
http://www.example.com/dir1/dir3.html Success 동일한 프로토콜, 호스트, 포트
http://www.example.com:81/dir/other.html Fail 다른 포트
http://en.example.com/dir/other.html Fail 다른 호스트
https://www.example.com/dir/other.html Fail 다른 프로토콜
http://v2.www.example.com/dir/other.html Fail 다른 호스트
http://example.com/dir/other.html Fail 다른 호스트

 

SOP 때문에 리소스를 공유하는 것은 불가능한것 처럼 보이지만, 기원이 갖지 않더라도 자원을 공유하는 모습을 웹에서 자주 볼 수 있다. 그 이유는 Cross Origin Resource Sharing(CORS)이라는 기능 덕분이다. 이 기능을 간단하게 설명하자면 SOP로 인한 자원 공유가 안되는 것에 예외를 두는 것이다.

Cross-Origin Resource Sharing

CORS는 SOP로 인한 제약사항을 완화해주는 역할을 한다. 즉, 다른 Origin임에도 리소스를 공유 할 수 있도록 도와준다. CORS를 허용해줄 때는 크게 2가지의 요청이 왔을 때의 반응을 정의한다.

  1. Simple Request: GET, HEAD, POST같은 Method와 Content-Type 헤더의 값이 text/plain, application/x-www-form-urlencoded 또는 multipart/form-data 일 때
  2. Non Simple Request: GET, HEAD, POST Method가 아닌 요청과 1. 에서 언급하지 않는 Content-Type으로 요청이 들어 왔을 때

Simple Request CORS

HTTP Request Method가 GET, HEAD, POST 중에 하나이며, Content-Type 헤더의 값이 text/plain, application/x-www-form-urlencoded 또는 multipart/form-data이면 Simple Request다.

Simple Request를 보낼때는 아래와 같이 Origin이 Header에 자동으로 추가되며 전송된다.

GET /tmp HTTP/1.1
Host: dyrandy.io
Origin: http://example.com
...

그리고 Server는 요청이 들어온 Origin과 Access-Control-Allow-Origin 헤더에서 허용하고 있는 Origin과 일치하는지 판별하고, 만약 다르다면 즉시 연결을 종료시킨다. (참고: Access-Control-Allow-Origin은 하나의 Origin만 정의할 수 있으며, 여러개일 경우 * 와일드카드를 사용한다.)

HTTP/1.1 200 OK  
Access-Control-Allow-Origin: http://example.com  
Content-Type: application/json
...

위와 같은 Header가 추가 되면 example.com이라는 Origin으로 부터 오는 모든 요청들을 허용해준다는 뜻이다.

Non Simple Request CORS

Simple Request가 아닌 것들은 전부 Non Simple Request로 분류 된다.

DELETE Method를 보낸다고 가정해보자. GET, HEAD, POST Method가 아니기 때문에 브라우저는 Preflight Request라는 것을 아래와 같이 Server에 보낸다.

OPTIONS /test HTTP/1.1
Origin: http://example.com
Access-Control-Request-Method: DELETE
...

그리고 Server는 이 Preflight Request가 허용됬는지 판단하고 응답을 보낸다.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET,DELETE,HEAD,OPTIONS
...

그러면 이제 DELETE Request를 보낼 수 있을 것이고, Simple Request와 동일하게 Header에 Origin정보가 적혀 있을 것이다.

JSONP

CORS만 SOP를 완화해주는 것이 아니다. JSONP(JSON With Padding)이라는 것도 있지만, 이것은 Read만 할 때 사용할 수 있으며, 복잡한 웹 구성에는 적합하지 않다.

CSP (Content Securiy Policy)

What Is CSP?

CSP는 Content Security Policy의 약자로 다양한 웹 보안 정책 중 하나다. 주로 XSS나 Data Injection, Click Jacking, 등 웹 페이지에 악성 스크립트를 삽입하는 공격기법들을 막기 위해 사용된다. 주로 헤더에(ex: “Content-Security-Policy: *”) 내용이 삽입되며 특정 리소스가 어디서 왔는지 검사를 하고 허용된 범위에 포함됐는지 검토를 한다.

How to check for CSP?

정말 간단하게 CSP가 걸려있는것과 걸려있는 정도를 파악해주는 사이트가 존재한다.

https://csp-evaluator.withgoogle.com/

그 외에도 헤더 정보를 보면 파악 할 수 있다.

Content-Security-Policy: * 같은 형식을 취한다. * 부분에는 다양한 주소들 혹은 설정들이 가능하다.

https://content-security-policy.com/

https://content-security-policy.com/

아주 가끔 메타 태그에 CSP를 넣는 경우도 있다고 한다.

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

How does CSP work?

CSP는 헤더에 어디서 정보들을 갖고 올 것인지 명시를 해준다. 아래 예제를 보자,

Example:

  1. Content-Security-Policy: default-src ‘self’
    모든 컨텐츠의 소스는 자기 도메인에서 갖고 오게 된다. 서브도메인은 제외다.
  2. Content-Security-Policy: default-src ‘self’ *.example.com
    모든 컨텐츠의 소스는 자기 도메인과 서브도메인에서 갖고 온다.
  3. Content-Security-Policy: default-src ‘self’; img-src *; media-src media1.com media2.com; script-src script.example.com;
    모든 컨텐츠는 자기 도메인에서 갖고 오지만 몇가지 예외 사항이 있다.
    1. img-src * : 이미지 관련 컨텐츠는 모든 사이트들을 허용한다.
    2. media-src media1.com media2.com : 미디어 관련 컨텐츠는 media1과 media2라는 사이트에서만 갖고 온다.
    3. script-src script.example.com : 실행 가능한 스크립트 관련 컨텐츠는 script.example.com에서만 갖고 온다.
  • script-src를 사용하지 않으면 script들은 오로지 서버에서 오는 것만 사용한다.

Directive Reference

  • default-src: 만약 다른 CSP들이 걸려 있지 않다면 Default로 설정되는 CSP다. Javascript, Image, CSS, Fonts, AJAX, 등 다양한 값들을 관리한다.
  • script-src: Javascript가 명시된 주소에서 왔는지 검사한다.
  • style-src: Stylesheet가 명시된 주소에서 왔는지 검사한다.
  • img-src: 이미지가 명시된 주소에서 왔는지 검사한다.
  • connect-src: XMLHttpRequest, WebSocket 등 검사한다.
  • font-src: 폰트가 명시된 주소에서 왔는지 검사한다.
  • object-src: <object>, <embed>, <applet> 같은 태그가 허용된 주소에서 왔는지 검사한다.
  • media-src: <audio>, <video>가 허용된 주소에서 왔는지 검사한다.
  • frame-src: 프레임이 허용됐는지 검사한다.
  • sandbox: SOP(Same Origin Policy)를 적용하고 팝업, 플러그인, 스크립트를 방지한다.
  • report-uri: 특정 주소로 browser가 정책실패로 인한 내용을 POST하게 만든다.
  • child-src: <frame>, <iframe>등을 검토해 웹 사이트 안에 삽입된 웹을 검토한다.
  • form-action: <form>의 소스를 검사한다.의 소스를 검사한다.

(위 이외에도 많은 종류들이 존재한다.)

Source List Reference

    • : 모든 도메인들을 다 허용한다.
  • 'none': 어디든 source를 가지고 오지 않는다.
  • 'self': 같은 기원에서만 source를 가지고 온다.
  • example.com: example.com에서만 source를 가지고 온다.
  • *.example.com: example.com과 example.com의 서브도메인에서만 source를 가지고 온다.

(위 이외에도 많은 종류들이 존재한다.)

https://content-security-policy.com/

https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

위 두 사이트를 참고하면 더 많은 내용들을 확인 할 수 있다.

Test

먼저 CSP의 작동을 확인해보자. 아래와 같은 간단한 코드로 이루어진 사이트가 있다고 가정해보자.

index.php

해당 주소로 접속하고 주소에, script tag, image tag, h1 tag를 각각 넣어보겠다.

  • Script Tag

script tag
script tag 반응

  • Image Tag

image tag
image tag 반응

  • H1 Tag

h1 tag
h1 tag 반응

먼저 첫 두 케이스를 보면 Javascript가 실행이 되면 CSP에 의해 바로 막히는 것을 확인 할 수 있다. 그 반면 일반 적인 태그는 그대로 삽입이 된다. script-src가 명시되어있지 않아 default-src를 기준으로 적용한다.

Bypass

1. CRLF Injection

가장 흔한 우회 방법 중 하나라고 생각한다. 방법은 매우 간단하다. 헤더의 정보를 우리가 임의로 수정할 수 있다면, CR(Carriage Return)과 LF(Line Feed)를 삽입하여 아래에 있는 헤더 정보를 header body로 보내 header정보를 무효화 시키는 것이다.

  • 사진은 이해를 돕기 위한 것입니다

Example 1
Example 2

위와 같이 사이에 CRLF를 둘 수 있다면 CSP를 Header의 Body로 인식시키게 만들어 무효화 시킬 수 있다.

2. Response Header (Status) Modification

다음 방법은 Header 변조다. 우리가 가장 흔히 아는 HTTP Status Code들은 200 OK, 500 Internal Server Error, 404 Not Found가 대표적이다. CSP는 간혹 Status Code에 따라 다르게 반응을 보인다.

아래와 같은 사이트가 있다고 가정해보자.

source code

요기서 우리는 header함수를 통해 header의 내용을 넣을 수 있다. 요기서 우리가 임의의 Status Code를 삽입 하면 어떻게 되는지 살펴보자. 먼저 Status Code가 없는 상태의 Response Header다.

  • 요기서 12번 줄이 10번 줄인 CSP 아래에 있던 위에 있던 상관 없다.

HTTP Response
Violoation

Status Code를 기본으로 사용하면 CSP가 걸리는 것을 확인 할 수 있다.

요기서 만약 Status Code를 내가 원하는 아무거나 입력 하면 어떻게 될가?

status code change
HTTP Response
XSS Bypass

위와 같이 CSP 내용이 Header에 있음에도 XSS가 터지는 것을 확인 할 수 있다.

다른 사이트들을 보면 400대에서나 500대에서도 CSP우회가 가능하다고 한다. (이번 실험에서도 해보았지만 안됐다. 그리고 h1이 아닌 h2에서 status code를 삽입하면 안된다.)

3. Adding Valid URL or Uploading to a Valid Server

가장 확실한 방법은 허용된 사이트에 스크립트를 삽입해서 불러오는 방법 혹은 허용되는 사이트를 추가해주는 방법이다.

아래와 같은 코드가 있다고 가정 해보자.

Source Code

우리가 원하는 주소를 위에 삽입 할 수 있다면, js가 업로드 된 주소를 가리켜 CSP를 우회할 수 있다.

URL

내 깃허브 주소를 가리켜 거기에 있는 js파일을 실행 시키도록 만들었다.

XSS

우회 방법이라고 보기에는 조금 애매하지만, 이런 경우가 종종 있어 확인해볼만한 것 같다.

참고

https://en.wikipedia.org/wiki/Content_Security_Policy

https://content-security-policy.com/

https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

https://www.hahwul.com/2019/01/csp-bypass-technique-xss.html

Comments