동일 출처 정책(SOP, Same Origin Policy)은 어떤 출처에서 불러온 문서/스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 방식이다.
즉, 동일한 출처에서만 리소스를 공유할 수 있다는 정책이다.
동일한 출처(origin)란?
두 URL의프로토콜
,포트
,호스트
가 모두 같은 경우 출처가 동일하다고 할 수 있다.
SOP의 존재 이유
이러한 제약이 없다면,CSRF
나XSS
등의 공격으로 의도하지 않았던 악성 출처에 아무런 제한 없이 접근할 수 있게 된다.
이러한 경우를 방지하기 위해 SOP 정책으로 동일하지 않은 출처에 접근할 수 없도록 하는 것이다.
이렇게 SOP에 의해 자신의 출처(프로토콜, 호스트, 포트)가 다른 출처는 차단된다.
이때, 출처 비교와 차단 로직은 브라우저에 구현되어 있는 스펙이다.
따라서 출처 비교와 차단은 서버가 아닌 브라우저
가 수행한다.
교차 출처 리소스 공유(Cross-Origin Resource Sharing)는 SOP에 대한 일종의 예외 사항으로, 다른 출처의 리소스 공유에 대한 허용 여부를 가르는 정책이다.
추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제
많은 정보를 담은 하나의 웹 페이지를 만들 때, 모든 내용을 한 출처에서 가져올 순 없을 것이다. 하지만 SOP 정책으로 인해 출처가 같은 곳에서만 리소스를 공유할 수 있는데, 이때 몇 가지 예외를 두어 출처가 다른 곳에서도 리소스를 공유받을 수 있게 해 주는 것이 CORS
다.
즉, SOP를 위반하더라도 CORS에 명시되어 있다면 다른 출처와의 리소스 공유를 허용한다는 것이다.
클라이언트에서 서버로 HTTP 프로토콜을 이용해 요청을 보낼 때, 요청의 헤더를 살펴보면 Origin
이라는 필드가 있는데 여기에 서버에 요청을 보내려는 출처가 담겨 있다.
다음은 localhost에서 특정 서버로 요청을 보냈을 때의 요청 헤더 부분이다.
클라이언트의 요청을 받은 서버는 응답을 보내게 되는데, 이때 응답 헤더에 서버 출처에 접근하는 것이 허용된 출처를 담아 응답한다. 이는 Access-Control-Allow-Origin
필드에 담겨 있다.
요청을 보내고 응답 헤더 부분을 살펴보면, 서버에서 ‘모든 출처에서 접근 가능하다’는 *
를 보내주었기 때문에 해당 요청은 다른 출처이지만 리소스를 획득할 수 있을 것이다.
브라우저는 요청의 Origin
과 Access-Control-Allow-Origin
을 비교하여 차단 여부를 결정한다. 이때 유효하지 않다면 CORS 에러가 발생하게 된다.
본 요청을 보내기 전에 미리 예비 요청을 보내 안전한 요청인지 확인한 다음 본 요청을 보내는 방식이다.
예비 요청은 OPTIONS
메서드로 보낸다.
브라우저의 preflight 요청은 네트워크 탭
에서 확인할 수 있다.
PreFlight의 요청 흐름은 다음과 같다.
OPTIONS
메서드로 preflight 요청을 보낸다.Origin
필드에 요청을 보내려는 출처를 담는다.Access-Control-Request-Method
필드에 사용하려는 메서드를 담는다.Access-Control-Request-Headers
필드에 사용할 헤더들을 담는다.Access-Control-Allow-Headers
필드에 허용하는 헤더들의 목록을 담는다.Access-Control-Allow-Methods
필드에 허용하는 메서드를 담는다.Access-Control-Allow-Origin
필드에 허용하는 Origin 목록을 담는다.Access-Control-Max-Age
필드에 해당 응답이 몇 초간 캐시될 수 있는지를 담는다.특정 조건이 만족되면 preflight 요청을 생략하고 바로 서버에 요청을 보내는 방식이다.
단순 요청을 보내기 위해 만족해야 할 조건은 다음과 같다.
GET
, HEAD
, POST
중 하나여야 한다.Accept
, Accept-Language
, Content-Language
, Content-Type
헤더의 값만 수동으로 설정할 수 있다.Content-Type
헤더에는 application/x-www-form-urlencoded
, multipart/form-data
, text/plain
값만 허용된다.위의 조건을 만족한 단순 요청의 흐름은 다음과 같다.
Access-Control-Allow-Origin
필드에 허용하는 Origin 목록을 담는다.요청 헤더에 인증 정보를 담아 보내는 요청 방식이다.
출처가 다를 경우 별도의 설정을 하지 않으면 쿠키를 보낼 수 없으며 클라이언트와 서버 양측 모두 CORS 설정이 필요하다.
withCredentials: true
를 넣어줘야 한다.Access-Control-Allow-Credentials: true
를 넣어줘야 한다.Access-Control-Allow-Origin
을 설정할 때 *
로 설정하면 에러가 발생한다.https://blog.4d.com/support-of-cross-origin-resource-sharing-cors/
https://evan-moon.github.io/2020/05/21/about-cors/