Same-origin Policy와 CORS

 

Same-origin Policy란?
  • 스크립트에 적용되는 정책이며, 스크립트 내에서 다른 리소스, 데이터를 요청할 때 요청지와 데이터 출처가 Same-origin이 아니면 막는 정책
  • 현재 스크립트를 실행하고 있는 주소와 (프로토콜, 호스트, 포트)가 동일한 주소를 Same-origin으로 판단한다.
    • 이는 브라우저가 `` document.domain``을 보고 판단함.

 

좀 더 정확히는, Cross-origin read를 막는다.
  • https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy#교차_출처_네트워크_접근
    • 교차 출처 쓰기는 보통 허용합니다.
      • Cross-origin으로의 링크, 리다이렉트, form submit 등
    • 교차 출처 삽입은 보통 허용합니다.
      • HTML 태그로 가져오는 항목(<script> 등), 글꼴(@font-face)
    • 교차 출처 읽기는 보통 불허 (ajax 등)
      • 하지만, 종종 교차 출처 삽입 과정에서 읽기 권한이 누출됩니다.
      • 예를 들면 삽입한 이미지의 크기나 삽입한 `` <script>``의 행동 등을 읽을 수 있습니다.
        • (*그래서 JSONP로 우회가 가능한 것)

 

왜 script에서 Cross-origin read를 막는가?
  • 단순히 Cross-origin으로 데이터 보내는걸 막고자 했다면 form submit도 막았어야 한다.
  • 마찬가지로 Cross-origin에서 데이터 가져오는 것 자체를 막고자 했다면, submit이나 삽입도 막았어야 한다.

 

그렇다면 왜 읽기만 불허할까?
  • 읽기를 불허한다는건, script 내에서 ajax 등을 이용해서 페이지 이동 없이 Cross-origin에서 데이터 받는 것을 막겠다. 라는 의미임.
  • 사실은 브라우저가 도메인 별로 쿠키를 관리하고, 해당 도메인에 접근 시 맞는 쿠키를 알아서 꺼내준다는 점과 관련이 있다.

 

생각해보면 다음과 같은 시나리오가 가능함.
  • 상황
    • 내가 1탭에는 구글을, 2탭에는 악성사이트를 띄워 둔 상태.
    • 2탭의 악성사이트 js에서는 접속자의 구글 계정 정보를 알아내고 싶어 한다.
    • 구글 계정 정보는 www.google.com/account로 요청을 보내야 얻을 수 있음.
  • 2탭의 js에서 form submit 요청을 보낸다면? www.google.com/account로 요청을 보낼 수는 있겠지만, 해당 정보를 악성사이트 개발자가 가져오지는 못한다. submit 하면서 페이지 이동이 발생하니 단순히 브라우저 상에서 유저가 클릭해서 들어간 것과 별 차이가 없으니까. 공격으로서 아무런 의미가 없다.
  • 반면 Same-origin Policy가 없어서 www.google.com/account로 ajax 요청이 가능하다고 가정해보자.
  • 2탭의 js에서 ajax로 www.google.com/account로 요청 보내면, 해당 도메인의 세션(쿠키)가 요청에 포함되어 전달되기 때문에 1탭에서 접근한 것과 동일하게 2탭에서 구글 계정 정보를 가져올 수 있다. 가져온 정보를 악성사이트로 submit하거나 또 다시 ajax로 보내는 것이 가능하다.

 

즉, 악성사이트가 정상사이트의 유저 세션(쿠키)을 이용해 정상사이트로부터 중요 정보를 획득하는 것을 막기 위해서

js 내에서 Cross-origin으로 read 요청을 보내는 것을 브라우저단에서 막아주는 것이 Same-origin policy.

라고 정리할 수 있다.

 

또는 이런 시나리오가 가능

  • 악성사이트에서 www.google.com/account에 대한 팝업을 생성
  • 구글의 window, location, document에 마음대로 접근 가능하다면, DOM에 접근해서 민감한 정보를 알아낼 수 있음.
  • 그래서 parent에서 child_popup.location 같은 변수에 접근하는 것은 불가능하다. (Cross-origin Read Block)

 

그럼 Cross-origin read가 필요한 경우 어떻게 해결할 수 있는가?

Cross-Origin Resource Sharing ( CORS ) 설정

 

CORS를 잘못 설정하는 경우?

1. account같이 개인 정보를 포함하고 있는 페이지인데, 서버에서 `` Access-Control-Allow-Origin: *`` 로 설정하는 경우.

이러면 어떤 악의적인 Origin에서 ajax 요청해서 개인정보를 받아갈 수 있음.

 

2. 또는 `` Origin = Access-Control-Allow-Origin`` 단순히 이렇게 설정하는 경우. 역시 위와 같이 악의적인 Origin에서 ajax 요청했을 때, ACAO 헤더에 악의적인 Origin 도메인이 들어가므로 브라우저가 받아들임.

 

 

클라이언트 사이드에서 JSONP

  • 가져오는 데이터가 JSON이어야만 한다는 제약이 있기는 함
  • 흔히 사용하는 ``html <script src=" (.js OR .json)"></script>`` 가 바로 JSONP다.
  • jQuery는 ``js $.ajax({dataType: 'jsonp'..``로 XHR 리퀘스트 형식처럼 사용할 수 있도록 지원한다.
  • front / back 둘 다 개발한다면 CORS를 사용하는 편이 더 낫겠지. 이건 약간 기믹같은 느낌이 들어서

 

기타

클라이언트가 직접 타 도메인에서 받아오는게 아니라, 서버 사이드에서 대신 타 도메인에 접근해 데이터를 받아온 다음, 이를 클라이언트에게 내려주는 방식도 있음.

기타 등등! https://en.wikipedia.org/wiki/Same-origin_policy#Relaxing_the_same-origin_policy

 

Cross-origin 접근 막기

https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy#교차_출처_접근_막기

  • 교차 출처 쓰기를 방지하려면 추측 불가능한 토큰을 요청에 포함하세요. 교차 출처 요청 위조(Cross-Site Request Forgery, CSRF) 토큰이라고 부릅니다. 토큰을 요구하는 페이지의 교차 출처 읽기도 막아야 합니다.
  • 리소스의 교차 출처 읽기를 방지하려면 삽입 불가하도록 설정하세요. 리소스 삽입 과정에서 일부 정보가 새어 나가므로 방지해야 합니다.
  • 교차 출처 삽입을 방지하려면, 리소스가 위에 나열한 삽입 가능 형태로 읽히지 않도록 해야 합니다. 브라우저는 Content-Type 헤더를 준수하지 않을 수도 있습니다. 즉, <script> 태그가 HTML 문서를 가리키도록 설정하는 경우, 브라우저는 HTML을 JavaScript로 분석하려고 시도합니다. 방지하려는 리소스가 사이트의 진입점이 아닌 경우 CSRF 토큰을 사용하는 것도 삽입 방지의 방법입니다.

 

'JS Stack > Front-end' 카테고리의 다른 글

webpack 빌드 - 독립 library로 만들기  (0) 2023.04.05
SameSite Cookie  (0) 2020.06.15
HTML5 data-* attribute  (0) 2018.11.23
[HTML] form tag, input 태그 속성  (0) 2017.06.10
[Front-end] Ajax  (0) 2017.05.28