Same-origin Policy와 CORS
- https://en.wikipedia.org/wiki/Same-origin_policy
- 영문 위키가 젤잘나와있음. 시나리오까지.
- W3C spec
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로 요청 보내서 계정 정보 가져오고, 이 정보를 악성사이트로 submit하거나 또 다시 ajax로 보낼 수 있음!
즉, 악성사이트가 정상사이트의 유저 세션(쿠키)을 이용해 정상사이트로부터 중요 정보를 획득하는 것을 막기 위해서
js 내에서 Cross-origin으로 read 요청을 보내는 것을 브라우저단에서 막아주는 것이 Same-origin policy.
라고 정리할 수 있다.
e.g., ) `` XMLHttpRequest`` 객체는 js 파일을 가져왔던 서버하고만 통신할 수 있다.
그럼 Cross-origin read가 필요한 경우 어떻게 해결할 수 있는가?
- Cross-Origin Resource Sharing ( CORS ) 설정
- 어떤 Cross-origin 리소스를 요청했을 때, 응답에 CORS HTTP 헤더가 있다면 CORS 설정이 되어있는 리소스로 판단하여 받아올 수 있다.
- 따라서 서버가 특정 리소스 요청에 대해서는 CORS 헤더를 추가하겠다! 라고 설정해주어야 함.
- https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
- https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/cors.html
- 클라이언트 사이드에서 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 토큰을 사용하는 것도 삽입 방지의 방법입니다.
'Languages & Frameworks > Front-end' 카테고리의 다른 글
SameSite Cookie (0) | 2020.06.15 |
---|---|
Same-origin Policy, CORS (0) | 2020.06.14 |
HTML5 data-* attribute (0) | 2018.11.23 |
[HTML] form tag, input 태그 속성 (0) | 2017.06.10 |
[Front-end] Ajax (0) | 2017.05.28 |
CSS Selector (0) | 2017.05.24 |