CORS는 cross origin resource sharing의 약자로
교차된 출처(Origin)의 자원을 공유할 수 있는 매커니즘(혹은 시스템)이다.
CORS에 관한 헤더 설정과 허용방법(모든 출처를 허용하는 방법..), XSS, CSRF을 막을 수 있다고 알고있었으나,
서브 도메인 여러 도메인을 포함하는 방법, XSS CSRF를 막을 수 없다는 것을 알게되어 CORS와 이들을 함께 설명하려고 한다.
CORS에 대해 설명하기 전 같은 출처에 대해서만 자원을 공유하도록 하는 정책인 SOP(Same Origin Policy)가 무엇인지와 왜 생겨나게 되었는지에 대해 알아보자.
SOP는 동일 출처에 대해서만 자원을 공유하도록 해주는 정책이다.
이는 1995년 Netscape에 의해 웹페이지에 스크립트 코드를 넣을 수 있게 해주는 "Javascript"가 등장한 이후로 발생가능한 스크립트를 이용한 공격들을 대처하기 위해 고안되었다.
추가로 SOP는 브라우저에 적용되는 보안 정책이다. 즉, Curl와 같은 명령어, PostMan과 같은 프로그램에서는 적용되지 않는데, 이는 위에서 언급한 것처럼 웹페이지에 심는 스크립트 공격을 대처하기 위해 존재하는 정책이기 때문이다.
기존에는 JSONP라는 script tag를 이용해 자원을 공유하는 트릭을 사용하였으나,
2009년부터 다른 출처에 대해 자원을 허용할 수 있는 CORS가 등장하게 되었다.
SOP, CORS에서는 Origin이라는 요소를 통하여 동일한 URL인지를 판단한다.
Origin은 scheme, host, port로 이루어져 있고
{scheme}://{host}:{port}로써 사용한다. 세 요소가 일치해야 같은 Origin으로 판단한다.
https://google.com:443의 경우
scheme: https
host: google.com
port: 443
이다.
※ https://cloud.google.com 과 같은 서브도메인은 다르게 판단한다.
Preflight
Simple Request
아래와 같은 조건에 모두 해당할 경우 Preflight 없이 요청만을 보낼 수 있고, 결과로 받은 응답 값을 통해 정책을 위반하는지를 확인한다.
조건
application/x-www-form-urlencoded
, multipart/form-data
, text/plain
의 컨텐츠 타입인 경우헤더 설정을 통해 어떻게 CORS를 적용할 수 있는지에 대해 살펴보자.
서버는 요청의 "Origin" 헤더를 통해 클라이언트의 URL을 식별하고
아래와 같은 헤더들을 설정하여 허용 여부를 표현할 수 있다.
*/*
처럼 모든 출처를 허용할 수도 있고, (권장 X)https://google.com:443
처럼 특정 출처를 허용할 수도 있다.https://*.google.com:443
처럼 서브 도메인을 허용하는 헤더는 작동하지 않는다.*.google.com
에 포함되면 해당 출처를 허용해주는 방식)allowedOriginPatterns
로 허용해줄 수도 있다고 한다.properties
파일을 통해 허용할 도메인 목록 작성서버의 Access-Control-Allow-Credentials: true
+ Access-Control-Allow-Origin
명시와 더불어
클라이언트에서의 withCredentials
설정을 통해 기존에 막혀있던 교차 출처간 인증 요청(쿠키, 세션, TLS 인증이 들어간 요청)을 허용할 수 있다.
XMLHttpRequest
의 경우 withCredentials
를 true
, false
로 쿠키 설정을 허용할 수 있고,Fetch의 경우 Request.credentials
를
same-origin
: 동일 출처에서만 허용include
: 다른 출처에서도 허용omit
: 모든 출처에서 비허용정답은 아니다. 물론 둘 다 아니다.
XSS의 경우는 어차피 허용된 도메인 내에 삽입된 스크립트로 하는 공격이기 때문에 출처에 영향을 크게 받지 않는다. (참고: 링크)
CSRF의 경우에도 SOP로가 읽기요청을 막는 것이지 쓰기 요청을 막는 것은 아니기 때문에 비밀번호를 변경하거나, 사용자의 권한을 바꾸는 등 쓰기 요청은 유효할 수 있다. (참고: 링크의 T.J. Crowder와 cifer의 답변)