CORS
의 정의교차 출처 리소스 공유(Cross-Origin Resource Sharing
, CORS
)는 브라우저가 추가 HTTP
헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.
쉽게 정리하자면, 사용자가 지금 접속한 사이트와 다른 출처의 릴소스를 사용하려 할 때, 브라우저가 참고하는 화이트 리스트라고 할 수 있다.
만약, 이 리스트에 없다면 콘솔 창에 빨갛게 CORS
에러를 마주하게 된다.
SOP
란?동일 출처 정책(Same-Origin Policy
)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식으로, 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여준다.
프로토콜 / 호스트 / 포트 3가지가 모두 동일하면 동일 출처라고 할 수 있다.
URL | 동일 출처 여부 |
---|---|
http://hhj.blog.com/dir/other | 기본 URL |
http://hhj.blog.com/dir3/other1 | 동일 출처 ⭕ - 경로만 다름 |
https://hhj.blog.com/dir/other | 동일 출처 ❌ - 프로토콜(https )이 다름 |
http://hhj.blog.com:81/dir/other | 동일 출처 ❌ - 포트가 다름 (기본 http:// 는 80, https:// 는 443) |
http://jhh.blog.com/dir/other | 동일 출처 ❌ - 호스트(jhh )가 다름 |
동일 출처가 아닌데 ajax
요청을 보내면 CORS error
를 만나게 되며, 즉, 동일 출처가 아닐 때 요청을 막는 것은 SOP
이고, 요청이 가능하도록 하는 것이 CORS
이다.
위의 그림을 통해 예시를 들자면,
유저가 어떤사이트에 접속하고 로그인을 하면, 브라우저의 토큰 등의 로그인 정보가 쿠키에 저장된다.
이때 로그인 했던 사이트에 접속할때 쿠키를 요청에 같에 보내어 로그인되었다고 판단한다.
즉, 인증 정보가 브라우저의 쿠키, 세션등의 스토리지에 저장되어 있고 이를 특정 요청에 같이 실어 보내어 인증을 진행하는 것이다.
만일 악의적인 사이트가 있다면 해당 사이트 접속시 JavaScript
코드가 유저의 브라우저에 다운로드되게 된다.
악의적인 사이트의 JavaScript
코드가 유저의 브라우저에 저장된 쿠키나 세션등에 접근할 수 있다.
이를 이용해 유저의 인증정보를 이용해 정보를 탈취할 수 있게된다.
원래 보안을 위해 다른 출처의 리소스를 접근하는 것이 불가능했지만, 웹 생태계가 다양해지면서 여러 서비스들끼리 자유롭게 데이터가 주고 받아질 필요가 생겼다.
그런데, 다른 사이트 간의 요청들을 브라우저가 막고 있기 때문에 이를 허용해주기 위해 어떠한 기준을 충족시키면 리소스를 공유할 수 있도록 만들어진 체제가 바로
CORS
다.
CORS
동작의 시나리오는 다음 2가지로 나뉜다.
Simple Request
예비 요청을 보내지 않고, 서버에게 바로 본 요청을 전송한다.
이 후 서버가 응답 헤더에
Access-Control-Allow-Origin
과 같은 값을 보내주면 그때 브라우저가 CORS 정책 위반 여부를 검사하는 방식이다.
GET
이나POST
등 일정 조건에 요청들에 대해 사용된다.
기본적으로 웹은 다른 출처의 리소스를 요청할 때는 HTTP
프로토콜을 사용하여 요청을 하는데, 이때 브라우저는 요청 헤더에 Origin
필드에 요청을 보내는 출처를 담아 전송한다.
서버는 요청에 대한 응답을 하는데, 응답 헤더에 Access-Control-Allow-Origin
이라는 항목에 이 리소스를 접근하는 것이 허용된 출처를 명시해준다.
Access-Control-Allow-Origin: *
처럼 와일드카드(*
)를 사용하면 모든origin
요청을 허용하는게 된다.
이후, 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin
과 서버가 보내준 응답의 Access-Control-Allow-Origin
을 비교한 후 이 응답 가능 여부를 결정한다.
요청 시 header
의 origin
항목에 URL
(프로토콜/호스트/포트) 정보가 담겨있고, 응답 header에 Access-Control-Allow-Origin 항목에 요청시 origin
항목의 URL 정보가 있다면 브라우저는 응답을 받아오게 되고 없다면, 거부하게되며 CORS error
가 나타나게 된다.
이러한 에러를 해결할 수 있도록, Spring
이나 Django
, Express
등의 문서에 CORS
옵션 설정하는 방법이 잘 나와있다.
Preflight Request
요청을 한번에 보내는 것이 아닌 예비 요청과 본 요청으로 나누어서 서버로 전송한다.
본 요청을 보내기 전 미리 예비로 보내는 요청을
Preflight
라고 하며,HTTP
메서드 중OPTIONS
메서드를 사용한다.서버는 예비 요청에 대한 응답으로, 어떤 요청을 허용하고 또 금지하는지에 대한 정보를 응답 헤더에 담아 보낸다.
예비 요청으로 본 요청이 안전한지 확인한 다음에야 본격적으로 요청을 보낼 수 있다.
PUT
이나DELETE
등 서버 데이터에 영향을 줄 수 있는 요청들이기 때문에 먼저 요청의 허용 여부를 검증하는 것이다.
만약, 토큰 등 사용자 식별 정보가 담긴 요청에 대해서는 보다 엄격하다.
요청 옵션에 crendentials
항목을 true
로 세팅해야 하고, 서버에서도 모든 출처를 허용하는 와일드카드 (*
)가 아닌 요청 웹페이지의 주소를 정확히 명시한 다음 Access-Control-Allow-Credentials
항목을 true
로 설정해주어야 한다.
참고 사이트