[ 기술 스터디 ] CORS 다시 정리하기

김민석·2021년 7월 13일
0

기술 스터디

목록 보기
13/18

면접에서 CORS 관련 질문이 나왔는데, 평소 알고 있는 것보다 훨씬 대답을 못했다. 나는 면접에서 알고있는 것의 반 정도... 만 이야기를 하는 수준이기 때문에 면접에서 얘기하고자 하는 것의 '두 배!!'를 공부해야한다.

오늘은 나 자신에게 조금 실망을 해서 좀 더 자세하게 정리해야겠다.

CORS란?

CORS : Cross-Origin Resource Sharing의 약자.
직역해보자면 교차 출처 리소스 공유
Origin에 대해 쓴 내 블로그

즉, CORS는 다른 origin에서의 리소스 요청을 허용하되, 이걸 가능하게 하려면 보안상의 이슈가 생기기 때문에 그 보안을 위해 만든 '기준'이 되겠다.

SOP(Same-Origin Policy)의 예외 조항이라고 생각해도 되겠다.

중요!

이 출처를 비교하는 로직은 브라우저에 구현되어 있는 스펙이다. 즉, 서버에서 같은 출처에서 보낸 요청만 받겠다는 로직이 구현되어 있지 않다면 서버는 정상적으로 응답을 하게 된다. 하지만 클라이언트가 이 응답을 분석해서 CORS 정책을 위반했을 때는 해당 응답을 버리게 된다.


CORS의 동작 방식

기본적으로 브라우저는 HTTP의 요청 헤더에 Origin 필드에 출처를 담아 보낸다.

이후 서버가 응답에 Access-Control-Allow-Origin이라는 값에 허용된 출처를 같이 보내고, 브라우저는 이것을 통해 응답이 유효한 응답인지 아닌지를 결정한다.

Preflight Request

Post 요청을 보냈을 때, 항상 봤던 요청이다.
아래와 헤더들을 갖고있다.

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

Preflight 요청 이후에 보낼 요청들에 대한 정보들을 함께 담고 있다는 것을 알 수 있다. (예를 들어 다음 요청이 Post 요청이라는 것을 알려주고 있다.)

다음은 응답 코드다.

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

만약 응답에 Access-Control-Allow-Origin에 'POST'가 빠져있었다면 브라우저에서는 CORS 에러를 볼 수 있다.

Simple Request

Preflight 요청 없이 진행되는 요청이다.
특정 조건을 만족시키면 단순 요청으로 보내지며, preflight을 보내지 않는다.
MDN 설명

Credentialed Request

fetch API나 axios에서 credentials 옵션을 건드리면 쿠키 정보 등을 헤더에 담아서 보낸다.

프로젝트를 할 때 몇 번 확인했던 오류다.

그런데 이렇게 하면 다음과 같은 오류가 뜰때가 있다.

Access to fetch at ’http://foo.example’ from origin ’http://bar.example’ has been blocked by CORS policy: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ’*’ when the request’s credentials mode is ‘include’.

개발 초기에는 대부분 Access-Control-Allow-Origin에 wildcard '*'를 할당해서 썼다. 그런데 인증 정보를 포함한 요청을 보내기 시작하면 이게 문제가 되는 것이다.

따라서 이때는 명시적인 URL을 지정해주어야 했다.


0개의 댓글