CORS에 대해 조사해서 나름대로 정리해본 글입니다.
틀린 부분이 있으면 언제든 댓글로 말씀해주세요🙃
Cross-Origin Resource Sharing
단순히 말하면, "다른 출처" 에서 받아오는 리소스를 제한하는 정책입니다.
여기서 출처(origin)란 url의 프로토콜+호스트+포트번호를 의미합니다.
3가지가 모두 동일한 출처를 same-origin이라고 하며, 3가지 중 하나라도 다르면 cross-origin이 됩니다.
중요한 점은, 출처를 비교하는 것은 서버가 아니라 브라우저입니다.
즉 CORS 정책을 위반하는 리소스 요청을 하더라도, 해당 서버가 same-origin만 허용하는 상태가 아니라면 서버는 정상적으로 응답을 하게 됩니다.
이 이후에 브라우저가 서버의 응답을 분석해서, CORS 정책 위반이라고 판단되면 그 응답을 사용하지 않고 버리는 순서인 것입니다!
SOP (Same-Origin Policy)
라는 정책이 웹에 존재합니다.
이는 동일한 출처에서만 리소스를 공유할 수 있음을 나타내는 보안정책입니다.
옛날에는 웹사이트를 만들 때 대부분 하나의 서버에서 브라우저의 모든 요청을 처리했기 때문에 이러한 정책이 존재하였습니다.
이러한 제약 정책 덕분에 사람들은 안전하게 인터넷을 사용할 수 있었습니다.
이러한 정책이 없다면, 아무나 나의 애플리케이션인 척 속여 서버로 요청을 보내 사용자의 정보를 빼내 갈 수 있을 것입니다.
하지만 점점 웹사이트에서 할 수 있는 일들이 많아지고, 다양한 출처의 리소스를 사용해야 할 일이 많아지게 되었습니다.
즉 cross-origin으로의 요청은 보안상으로 제한되었지만, 이러한 요청이 필수적이게 된 것입니다.
그래서 SOP에 몇 가지 예외 조항을 두고, 이 조항에 해당하는 리소스 요청은 출처가 다르더라도 허용하기로 한 것인데, 그중 하나가 CORS 정책을 지킨 리소스 요청
입니다. 즉 우리는 CORS로 인해 다른 출처의 리소스에 접근하여 사용할 수 있는 것입니다.
CORS로 인해 발생하는 문제를 해결하기 위해서는, 먼저 CORS의 동작 방법부터 이해해야 합니다.
기본적으로 웹 클라이언트 애플리케이션이 다른 출처의 리소스를 요청할 때에는 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이때 브라우저는 요청 헤더의 Origin 이라는 필드에 요청을 보내는 출처를 함께 담아 보내게 됩니다.
ex) Origin : https://github.com
이후 서버가 이 요청에 대한 응답을 할 때 응답 헤더의 Access-Control-Allow-Origin
이라는 값에 "이 리소스를 접근하는 것이 허용된 출처"를 내려주고, 이후 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin를 비교해본 후 이 응답이 유효한지 결정합니다.
기본적인 흐름은 이렇고, 구체적인 동작 방식은 다시 2가지로 나뉘게 됩니다.
단순 요청 방법으로, 서버에게 바로 요청을 보내는 방법입니다.
서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보냅니다.
브라우저는 이 헤더를 확인해서 CORS 동작을 수행할지 판단합니다.
하지만 서버로 전달하는 요청이 꽤나 까다로운 조건을 만족해야 단순 요청으로 동작하게 됩니다.
일반적인 웹 애플리케이션 개발 시에는 거의 충족하기 어려운 조건들이라 경험하기에는 어려움이 있습니다.
서버에 예비요청(preflight)을 보내서 안전한지 판단한 후 본 요청을 보내는 방법으로, 가장 일반적인 방법입니다.
preflight 요청은 실제 리소스를 요청하기 전에, OPTIONS
이라는 메서드를 통해 실제 요청을 전송할지 판단합니다.
OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보냅니다.
브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단합니다.
안전하다고 판단되면 다시 본 요청을 보내게 됩니다. 이후 서버가 이 본 요청에 대한 응답을 하면 브라우저는 최종적으로 이 응답 데이터를 자바스크립트에게 넘겨주게 됩니다.
이제는 CORS의 해결 방법 2가지에 대해서도 이해할 수 있습니다.
서버에서 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있습니다.
즉 프론트엔드 개발자가 CORS 에러를 확인하면 서버에 Access-Control-Allow-Origin 등 CORS를 해결할 수 있는 몇 가지 응답 헤더를 포함해달라고 요청하면 됩니다.
Access-Control-Allow-Origin 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용하게 되며, Access-Control-Allow-Origin:https://github.com
과 같이 출처를 명시해주면 됩니다.
요약하자면, Cross Origin에서 자원을 요청하기 위해서는 다음과 같은 과정을 거치면 됩니다.
- Http 통신 헤더인 Origin 헤더에 요청을 보내는 곳의 정보를 담고, 서버로 요청을 보낸다.
- 이후 서버는 Access-Control-Allow-Origin 헤더에 허용된 Origin이라는 정보를 담아 보낸다.
- 클라이언트는 헤더의 값과 비교해 정상 응답임을 확인하고 지정된 요청을 보낸다.
- 서버는 요청을 수행하고 200OK코드를 응답한다.
이 방법은 서버에서 설정하는 방법으로, 프론트엔드단에서는 불가능합니다.
CORS를 겪는것은 프론트엔드 부분이므로, 프론트엔드단에서 이를 해결하기 위해서는 proxy를 사용합니다.
프록시를 이용하여 CORS 정책을 지킨 것처럼 브라우저를 속이면서, 원하는 서버와 통신을 할 수 있게 되는 것이죠.
자세히 설명하면, 프론트엔드와 백엔드 사이에 프록시 서버를 두는 방법으로 CORS를 우회하는 것입니다.
즉 브라우저는 localhost에서 요청을 보낸 것으로 알고 있지만, 뒤에서 https://github.com
로 요청을 프록싱해주어서 마치 CORS 정책을 지킨 것처럼 브라우저를 속이면서도 원하는 서버와 자유롭게 통신을 할 수 있게 됩니다.
프론트엔드단에서 해결 가능한 방법이지만, 로컬개발환경과는 달리 실제 애플리케이션을 빌드 후 서버에 올리게되면 프록싱이 먹히지 않습니다.
즉 근본적인 해결 방법은 아니므로 1번 방법을 기억하는 게 좋을 것 같습니다.
스스로 CORS에 대해 조사한 내용을 정리해본 내용이므로 부족하거나 틀린 내용이 있을 수 있습니다.🙃