Studying Security

Same Origin Policy(SOP) 본문

Web

Same Origin Policy(SOP)

J4guar 2022. 7. 17. 11:42
728x90
반응형

브라우저가 웹 서비스에 접속할 때 브라우저는 자동으로 쿠키를 헤더에 포함시켜 요청을 보내기 때문에 포털 사이트, SNS와 같은 웹 서비스에 한 번 로그인한 후 일정 기간은 로그인하지 않고도 바로 서비스를 사용할 수 있습니다.

 

브라우저

  • 인증 정보로 사용될 수 있는 쿠키를 브라우저 내부에 보관합니다.
  • 이용자가 웹 서비스에 접속할 때, 해당 웹 서비스에서 사용하는 인증 정보인 쿠키를 HTTP 요청에 포함시켜 전달합니다.(이와 같은 특징은 사이트에 직접 접속하는 것에만 한정되지 않습니다.)
  • 웹 리소스를 통해 간접적으로 타 사이트에 접근할 때도 인증 정보인 쿠키를 함께 전송하는 특징을 가지고 있습니다.

위의 특징 때문에 악의적인 페이지가 클라이언트의 권한을 이용해 대상 사이트에 HTTP 요청을 보내고, HTTP 응답 정보를 획득 하는 코드를 실행할 수 있습니다. (위협 요소)

따라서, 클라이언트 입장에서는 가져온 데이터를 악의적인 페이지에서 읽을 수 없도록 해야 합니다.

 

이와 같은 문제를 방지하기 위해 동일 출처 정책, Same Origin Policy (SOP) 보안 메커니즘이 탄생했습니다.

 

오리진(Origin) =  프로토콜 (Protocol, Scheme) + 호스트(Host) + 포트 (Port)

구성 요소가 모두 일치해야 동일한 오리진(Origin)이라고 합니다. 

https://same-origin.com/ 이라는 Origin을 기준으로 비교

Same Origin 데이터 읽기 O

Cross Origin 데이터 읽기 X / 데이터 쓰기 O

Cross Origin Resource Sharing (CORS)

SOP는 클라이언트 사이드 웹 보안에서 중요한 요소입니다.

하지만, 브라우저가 이러한 SOP에 구애 받지 않고 외부 출처에 대한 접근을 허용해주는 경우가 존재합니다.

  • 예를 들면, 이미지나 자바스크립트, CSS 등의 리소스를 불러오는 <img>, <style>, <script> 등의 태그는 SOP의 영향을 받지 않습니다.
  • 웹 서비스에서 동일 출처 정책인 SOP를 완화하여 다른 출처의 데이터를 처리 해야 하는 경우도 있습니다.
    • 이와 같은 상황에서 자원을 공유하기 위해 사용할 수 있는 방법을 교차 출처 리소스 공유(CORS)라고 합니다.

교차 출처의 자원을 공유하는 방법

  • CORS와 관련된 HTTP 헤더를 추가하여 전송하는 방법
  • JSON with Padding (JSONP) 방법

교차 출처 리소스 공유 (Cross Origin Resource Sharing, CORS)HTTP 헤더에 기반하여 Cross Origin 간에 리소스를 공유하는 방법입니다. 발신측에서 CORS 헤더를 설정해 요청하면, 수신측에서 헤더를 구분해 정해진 규칙에 맞게 데이터를 가져갈 수 있도록 설정합니다.

발신측에서 POST 방식으로 HTTP 요청을 보냈으나, OPTIONS 메소드를 가진 HTTP 요청이 전달된 것을 확인할 수 있습니다. 이를 CORS preflight라고 하며, 수신측에 웹 리소스를 요청해도 되는지 질의하는 과정입니다.

 

웹 리소스를 요청하는 발신측 코드의 일부

/*
    XMLHttpRequest 객체를 생성합니다. 
    XMLHttpRequest는 웹 브라우저와 웹 서버 간에 데이터 전송을
    도와주는 객체 입니다. 이를 통해 HTTP 요청을 보낼 수 있습니다.
*/
xhr = new XMLHttpRequest();
/* https://theori.io/whoami 페이지에 POST 요청을 보내도록 합니다. */
xhr.open('POST', 'https://theori.io/whoami');
/* HTTP 요청을 보낼 때, 쿠키 정보도 함께 사용하도록 해줍니다. */
xhr.withCredentials = true;
/* HTTP Body를 JSON 형태로 보낼 것이라고 수신측에 알려줍니다. */
xhr.setRequestHeader('Content-Type', 'application/json');
/* xhr 객체를 통해 HTTP 요청을 실행합니다. */
xhr.send("{'data':'WhoAmI'}");

발신측의 HTTP 요청

 "Access-Control-Request"로 시작하는 헤더가 존재하는 것을 확인할 수 있습니다. 해당하는 헤더 뒤에 따라오는 Method와 Headers는 각각 메소드와 헤더를 추가적으로 사용할 수 있는지 질의합니다.

OPTIONS /whoami HTTP/1.1
Host: theori.io
Connection: keep-alive
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://dreamhack.io
Accept: */*
Referer: https://dreamhack.io/

서버의 응답

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://dreamhack.io
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type

위 과정을 마치면 브라우저는 수신측의 응답이 발신측의 요청과 상응하는지 확인하고, 그때야 비로소 POST 요청을 보내 수신측의 웹 리소스를 요청하는 HTTP 요청을 보냅니다.

JSON with Padding (JSONP)

좀 전에 이미지나 자바스크립트, CSS 등의 리소스는 SOP에 구애 받지 않고 외부 출처에 대해 접근을 허용한다고 하였습니다. JSONP 방식은 이러한 특징을 이용해 <script> 태그로 Cross Origin의 데이터를 불러옵니다.

하지만 <script> 태그 내에서는 데이터를 자바스크립트의 코드로 인식하기 때문에 Callback 함수를 활용해야 합니다. Cross Origin에 요청할 때 callback 파라미터에 어떤 함수로 받아오는 데이터를 핸들링할지 넘겨주면, 대상 서버는 전달된 Callback으로 데이터를 감싸 응답합니다.

다만 JSONP는 CORS가 생기기 전에 사용하던 방법으로 현재는 거의 사용하지 않는 추세이기 때문에, 새롭게 코드를 작성할 때에는 CORS를 사용해야 합니다.

<script>
/* myCallback이라는 콜백 함수를 지정합니다. */
function myCallback(data){
    /* 전달받은 인자에서 id를 콘솔에 출력합니다.*/
	console.log(data.id)
}
</script>
/*
https://theori.io의 스크립트를 로드하는 HTML 코드입니다.
단, callback이라는 이름의 파라미터를 myCallback으로 지정함으로써
수신측에게 myCallback 함수를 사용해 수신받겠다고 알립니다.
*/
<script src='http://theori.io/whoami?callback=myCallback'></script>
/*
수신측은 myCallback 이라는 함수를 통해 요청측에 데이터를 전달합니다.
전달할 데이터는 현재 theori.io에서 클라이언트가 사용 중인 계정 정보인
{'id': 'dreamhack'} 입니다. 
*/
myCallback({'id':'dreamhack'});

Reference

반응형

'Web' 카테고리의 다른 글

SQL Injection: DBMS  (0) 2022.07.18
Cross Site Request Forgery(CSRF)  (0) 2022.07.18
Cookie & Session  (0) 2022.07.16
Cross Site Script(XSS)  (0) 2022.07.15
Comments