세 가지를 모두 합친 것을 의미합니다.
이 세 가지 중 하나라도 다르면, 브라우저는 두 출처가 서로 다르다고 판단합니다.
예를 들어 https://my-domain.com에서 다른 곳으로 요청을 보낼 때,
https://my-domain.com/posts →
(성공)
출처가 완전히 동일합니다.
http://my-domain.com →
(실패)
프로토콜이 다릅니다. (https vs http)
https://api.my-domain.com →
(실패)
호스트(서브도메인)가 다릅니다.
https://my-domain.com:8080 →
(실패)
포트가 다릅니다.
이 정책이 없다면, 만약 여러분이 악성 사이트에 접속했을 때 그 사이트의 스크립트가 여러분의 은행 사이트에 멋대로 요청을 보내 개인정보를 탈취하는 끔찍한 일이 벌어질 수 있습니다.
SOP는 이렇게 다른 출처의 리소스를 함부로 읽어오지 못하게 막아주는 아주 중요한 보안 장벽입니다.
SOP는 보안에 필수적이지만, 현대 웹 개발에서는 API 서버를 별도로 두는 등 다른 출처의 리소스가 필요한 경우가 아주 많습니다.
CORS
는 바로 이럴 때를 위해 만들어진 정책입니다.
CORS는 SOP라는 보안 원칙을 지키면서도,
서버와 클라이언트가 서로 합의하여 안전하게 다른 출처의 리소스를 공유할 수 있도록 허용해주는 메커니즘
입니다.
중요한 점은, CORS는
서버
가 설정하는 정책이라는 것입니다.
서버가 자신의 응답 헤더에 Access-Control-Allow-Origin과 같은 특정 정보를 담아 보내주면, 브라우저는 이 헤더를 보고 "아, 이 서버는 다른 출처의 요청을 허용하는구나"라고 판단하고 리소스 접근을 허락해 줍니다.
CORS 에러는 서버가 허락하지 않았는데 브라우저가 막는 상황이므로, 해결은 항상 서버 측에서 이루어져야 합니다.
단순 요청의 조건을 만족하지 않는, 서버의 데이터에 영향을 줄 수 있는 '잠재적으로 위험한' 요청들입니다.
(예: PUT, DELETE 메서드, Content-Type: application/json, 커스텀 헤더 포함 등)
이 경우 브라우저는 실제 요청을 보내기 전에, 먼저
프리플라이트(Preflight)
라는 예비 요청을 보내 서버의 허락을 구합니다.
마치 중요한 손님이 방문하기 전에, 비서가 먼저 전화를 걸어 "이런 분이 이런 용무로 방문해도 괜찮을까요?"라고 물어보는 것과 같습니다.
동작 흐름
브라우저는 실제 요청을 보내기 전에, 먼저 OPTIONS라는 HTTP 메서드를 사용하여 예비 요청(프리플라이트)을 서버에 보냅니다.
이 예비 요청에는 앞으로 보낼 실제 요청의 메서드(Access-Control-Request-Method)와 헤더(Access-Control-Request-Headers) 정보가 담겨있습니다.
서버는 이 OPTIONS 요청을 받고, 자신의 CORS 정책에 따라 어떤 메서드와 헤더를 허용하는지 응답 헤더(Access-Control-Allow-Methods, Access-Control-Allow-Headers 등)에 담아 응답합니다.
브라우저는 이 프리플라이트 응답 헤더를 확인합니다.
만약 서버가 앞으로 보낼 실제 요청을 허용한다고 판단되면,
그때서야 실제 요청(예: PUT 요청)을 서버에 보냅니다.
만약 서버가 허용하지 않으면, 브라우저는 실제 요청을 보내지 않고 CORS 에러를 표시합니다.
이라는 보안 규칙 때문에 필요합니다.
SOP는 기본적으로 다른 출처의 리소스 요청을 차단하여 보안을 지키지만, 현대 웹에서는 API 서버 분리 등 다른 출처의 리소스가 필요한 경우가 많습니다.
CORS는 서버가 특정 다른 출처를 신뢰한다고 명시적으로 알려주어, 브라우저가 안전하게 SOP의 예외를 허용하도록 만드는 메커니즘입니다.
프리플라이트 요청은 브라우저가 실제 요청을 보내기 전에 서버가 해당 요청을 허용하는지 미리 확인하는
예비 요청
입니다.
이 요청은 HTTP의 OPTIONS 메서드를 사용합니다.
단순 요청(Simple Request)의 조건을 벗어나는, 예를 들어 PUT이나 DELETE 메서드를 사용하거나, Content-Type이 application/json이거나, 커스텀 헤더가 포함된 요청을 보낼 때 발생합니다.
서버가 이 OPTIONS 요청에 대해 허용한다는 응답을 보내야만, 브라우저는 비로소 실제 요청을 서버로 보냅니다.
원칙적으로 CORS는 브라우저가 서버의 응답 헤더를 보고 판단하는 정책이므로, 근본적인 해결은
서버 측에서
이루어져야 합니다.
서버의 응답 헤더에 Access-Control-Allow-Origin과 같은 올바른 CORS 관련 헤더를 추가해 주어야 합니다.
물론 개발 환경에서는 프록시 서버를 사용하여 요청의 출처를 속이는 방식으로 우회할 수는 있지만, 이는 임시방편일 뿐 실제 프로덕션 환경에서의 해결책은 아닙니다.