란? §
- 일단 SOP (Same Origin Policy) 에 대해 짚고 넘어가면
- SOP의 경우에는 뭐 당연하게도 어지간한 문제가 발생하지 않는다 → 출처가 같은데 뭐 더 할게 있나
- 하지만 웹상에서는 같은 출처의 정보만 이용해서 뭔가를 하기에는 너무 힘들고 비효율적이기 때문에 다른 출처의 정보도 가져다가 사용하는 것을 일부 허용한다.
- ‘일부’ 란 말을 굳이 한 이유는 제한된 (예외적인) 상황에서만 이게 허용되기 때문이다.
- 무지성으로 전부다 되는게 아니다 이거야
- 이 예외사항을 명시한게 CORS (Cross-Origin Resource Sharing) 이다.
- 즉, Origin (Scheme/Protocol + Host + Port) 가 다른 요청에 대해 응답받은 자원을 사용할까 말까에 대한것이다.
Origin 판단 규칙 §
- Protocol(Scheme) + Host + Port 세가지로 판단하기는 하는데
- 포트에 대해서는 생략할 수도 있고 브라우저마다 구현방식이 달라 좀 애매하다
- 하지만 포트까지 같다면 무조건 같은 출처이기 때문에 걍 포트까지 다 맞춰라 (앵간하면 포트가 다르면 다른 출처로 판단하긴하더라)
CORS 작동원리 (일반 요청) §
- 일단 가장 핵심은 CORS 를 판단하는 주체는 브라우저라는 것이다
- 즉, 서버에서
200
으로 줘도 CORS 에러가 날 수 있다.
- 일반적인 경우에 CORS 가 판단되는 과정은 다음과 같다
- 클라이언트는 서버에게 Preflight 을 날린다
- 너가 몰랐던 내용일텐데 이전에 OPTIONS HTTP Method 가 어디 사용되는지 궁금해했었제?
- 클라이언트가 서버에게 날리는 (거의 모든) 요청에는 Preflight가 먼저 날라가서 요청이 가능한지 확인하고
- 요청이 가능할때 본 요청이 날라가는 방식으로 작동한다.
- 이때 사용되는 HTTP Method 가 OPTIONS 이며 요청이 가능한지 확인하는 것 외에도 어떤 HTTP Method 를 사용할 것인지, 어떤 헤더를 보낼 것인지 서버에게 미리 알려주는 역할도 한다
- 어쨋든 CORS 에서의 Preflight 의 핵심은 클라이언트의
Origin
헤더를 request header 에 붙여서 보내고, 서버는 response header 에 Access-Control-Allow-Origin
헤더로 CORS 를 허용하는 Origin 들을 알려주는 방식으로 Preflight 가 진행된다.
- 즉, 이 시점에는 CORS Validation 이 이루어지지 않는다 → 걍 클라이언트는 클라이언트대로 설정된 Origin 을 보내고 서버는 서버 대로 설정된 CORS Allow Origin 만을 보낸다
- Preflight 이후 브라우저는 Request header 의
Origin
헤더와 Response header 의 Access-Control-Allow-Origin
헤더를 비교하며 CORS 를 체크한다
- 만일 두 값이 다르거나
Access-Control-Allow-Origin
이 설정도어있지 않으면 CORS 에러를 뱉는다.
- Preflight 에서 CORS 가 발생했을 때는 본 요청을 보내지 않고 끝난다.
CORS 작동원리 (인증 요청) §
- 아마 로그인 구현하면서 이부분때문에 아주 애를 먹었을텐데
- 일단 기본적으로
fetch()
이나 XMLHttpRequest
는 인증과 관련된 헤더나 쿠키를 CORS 요청에 담지 않는다
- 만일 담고싶은 경우에는
credentials
옵션을 설정해줘야 한다 → 얘는 HTTP 헤더는 아닌거같은데
- 일단 default 는
same-origin
이다 → 즉, 출처가 같으면 당연히 인증 혹은 쿠키가 담긴다
include
는 CORS 한 환경에서도 담을 수 있도록 해주는 옵션이고
omit
은 절대 담지 않는다는 거다
- 그래서 너가
include
로 설정해서 요청을 날리면 되긴 하는데 이때에는 CORS Validation 에 한가지 제약이 더 붙는다
- 바로 →
Access-Control-Allow-Origin
헤더의 값이 *
면 안된다는 것
- 즉, 모든 출처를 순풍순풍 받아들이겠다는
*
값은 include
일때는 사용할 수 없다
- 따라서 반드시 허용할 출처를 명확히 명시해주어야 한다
- 정리해보면 다음과 같음 → 쿠키나 인증을 클라이언트 - 서버 간 와리가리하고싶다면
- 클라이언트에는
credentials: include
로 설정해주어야 한다
- 서버에는
Access-Control-Allow-Origin
값으로 *
가 아닌 명확한 출처를 헤더에 넣어야 한다.
추가적으로 읽어볼만한 §