💬 들어가며
프로젝트를 진행하면서 초반에 가장 많이 발생했던 CORS 이슈에 대해 확실히 짚고 넘어가기 위해 정리해보려 한다.
CORS, Cross-Origin Resource Sharing 이라는 정책으로 웹 개발자라면 흔히 겪는 에러의 원인이라고 과언이 아니라고 한다. 실제로 서버와 통신을 진행해서 프로젝트를 진행해 본 경험이 없었던 나는 에러가 발생했을 당시 당황스러웠던 기억이 많다.
CORS는 쉽게 말해서 '다른 출처 간의 리소스를 공유하는 것에 대한 정책' 을 의미한다. 이 정책 덕분에 다양한 곳에서 가져오는 리소스가 안전하다는 최소한의 보장을 받을 수 있다.
실제로 어떤 방법을 통해 리소스를 안전하게 사용할 수 있는지 알아보자.
기본적으로 클라이언트가 리소스를 요청할 때에 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이때 브라우저는 Request Header
에 서버에 요청을 보내는 출처가 담긴 Origin
이라는 필드를 함께 담아보낸다.
실제로 진행 중인 프로젝트에서도 API를 통해 데이터를 요청할 때의 헤더 내용을 다음과 같이 확인할 수 있었다.
이후 서버는 이 요청에 대해 응답을 할 때 Response Header
에
Access-Control-Allow-Origin
이라는 필드에 '요청 리소스에 접근이 허용된 출처'를 담게 되고, 이후 응답을 받은 브라우저는 Request Header
에 담았던 Origin
과 Access-Control-Allow-Origin
필드의 값을 비교해보며 응답이 유효한지에 대해 결정하게 된다.
위 방식이 기본적인 CORS의 흐름이다. 하지만, CORS가 동작하는 방식은 3가지가 존재하기 때문에 개발하는 상황에 따라 자신이 어떤 시나리오에 적용되어있는지 파악한다면 에러를 고치는 것이 한결 쉬워질 것이다.
가장 많이 마주치는 시나리오는 프리플라이트 요청 방식이다. 이 방식은 브라우저가 본 요청을 보내기 전 예비 요청인 Preflight를 보내면서 요청이 안전한 것인지 확인하는 과정을 거친다. 이 예비 요청에는 HTTP 메소드 중 OPTIONS
메소드가 사용된다. 위에서 첨부한 캡처사진 또한 Preflight 요청이기에 OPTIONS
메소드를 사용하는 것을 확인할 수 있다!
다음으로 눈여겨 보아야 할 것은 예비 요청에 대해 서버가 보낸 응답 헤더에 포함된 Access-Control-Allow-Origin
필드이다. 요청 헤더에서의 Origin 필드의 출처와 응답 헤더에서의 ACAO 필드의 값이 동일한 것을 확인할 수 있다. 만약, ACAO 필드에서 허용하지 않는 출처를 Origin에 담았다면 CORS 정책을 위반하게 되어 에러를 뱉어내게 되는 것이다.
단순 요청이다. 예비 요청 없이 본 요청을 바로 서버에 보낸다. 이후 ACAO 필드를 확인해서 통신하는 방식은 Preflight 요청 방식과 같다.
하지만 아무 때나 단순 요청이 가능하지 않고, 아래와 같은 특정 조건을 만족하는 경우에만 예비 요청을 생략할 수 있다.
Authorization
필드를 사용하므로 이 경우 조건을 만족시킬 수 없다. application/json
이나 text/xml
을 사용하기 때문에 3번 조건 또한 만족시키기 어려운 경우가 많다고 한다.다른 방법들과 달리 추가 인증을 통해 좀 더 보안을 강화하는 방법이다.
기본적으로 비동기 리소스 요청 API인XMLHttpRequest
나 Fetch
호출을 통해서 브라우저는 자격 증명, 즉 인증과 관련된 헤더를 함부로 요청에 담아 보내지 않는다. 이때 인증 관련 정보를 담을 수 있게 해주는 옵션이 바로 credentials
옵션이다.
자세한 정보는 참고 블로그를 통해 더 알아볼 수 있다.