스터디에서 CORS에 대해 발표한 내용을 정리한다.
발표 자료 LINK
Cors란 Cross-Origin Resource Sharing의 약자로 <교차 출처 리소스 공유>라는 의미다. 좀 더 풀이하면, 다른 도메인과 데이터를 공유하는 것을 허용한다는 각 브라우저에서 시행하는 정책이다(웹 표준이 아니다).
웹 기반 프로젝트를 할 때 다른 서버에서 데이터를 요청하면 이런 에러를 볼 수 있다.
'http://localhost:3000'에서 'https://joke-api-strict-cirs(이하 생략)'에 접속하는 행위는 CORS 정책에 의해 금지된다: 요청된 데이터에 'Access-Control-Allow-Origin' 헤더가 없으니 리소스를 가져올 때 CORS가 작동하지 않도록 요청 모드를 'no-cors'로 변경해라.
정리하면 'Cors 정책때문에 다른 도메인에서 데이터를 가져올 수 없으니 이러저러하게 설정을 해라' 라는 의미다. Cors가 다른 도메인과의 데이터를 공유하게끔 하는 정책이니, 이를 설정해야 통신을 원활하게 할 수 있을것 같다. 그 이전에, 이런 에러메세지를 보기 위해서는 리소스가 '다른 도메인(cross-origin)'에 있어야만 한다. 어떤 도메인을 same-origin이라고 하는지, cross-origin이라고 하는지 그 기준에 대해 알아보자.
출처(Origin)는 크게 Protocol, Host, Port, query string 네 범주로 구분되는데, 이 중에서 Protocol, Host, Port가 일치하면 출처가 같다고 표현한다. 이 중 하나라도 어긋날 경우 Cross-origin으로 간주한다. 주의할 점은 Cors가 브라우저에서 시행하는 정책이라 브라우저마다 기준이 조금씩 다르다는 것인데 일반적으로는 이런 기준을 사용하고 있다.
Cors를 이해하려면 Cors를 어떤 배경에서 사용하게 되었는지를 이해해야 한다
SOP는 동일 출처 정책 이라는 의미로 Cors와 마찬가지로 브라우저에서 시행하는 정책이며 동일 출처 간에만 리소스를 공유할 수 있도록 하는 보안 메커니즘이다. Origin의 기준은 Cors처럼 Porotocol, host, port다. SOP는 다른 도메인, 확인되지 않은 도메인에 요청을 보냈다가 보안상 문제가 생길 수 있어 이런 문제를 미연에 방지하기 위해 만들어진 정책이다. 하지만 웹이 점점 발전할수록 도메인간의 통신은 피할 수 없는데, 이를 위해 SOP를 완화해 다른 출처 간에도 통신할 수 있도록 하는 방안중 하나가 Cors다. 위에서 본 에러는 기본적으로 브라우저에는 SOP가 통용되고 있는데, Cors 정책을 사용하기 위한 조건을 만족시키지 못했기 때문에 발생했음을 알 수 있다.
Cors의 동작 방식은 크게 세 가지인데, 조건과 쓰임새에 따라 달리 사용된다. 여기서는 Simple과 Preflight 요청 방식만 기술한다.
Simple Request는 과정이 단순한 만큼 조건이 까다롭다.
위 조건을 충족하면 Simple Request 방식으로 서버에 요청할 수 있다. 또한 서버는 헤더에 Access-Control-Allow-Origin를 포함해 응답하는데, 브라우저가 응답을 받았을 때 Access-Control-Allow-Origin의 값이 * 이면 모든 도메인에서 접근 가능한 리소스라는 의미로, 접근에 제한이 없다는 뜻이다. 특정 도메인만 접근 가능하도록 하고 싶다면 값에 도메인을 넣는다.
💁♀️과정 정리
1. 위 조건을 충족한 요청 API를 브라우저가 서버에 전송한다.
2. 서버는 요청 API를 검토한 뒤 응답 헤더에 Access-Control-Allow-Origin를 포함해 전송한다. 이때 서버가 전송하는 응답은 요청API를 처리한 결과물을 포함하고 있다.
3. 브라우저는 서버의 응답 API를 받아 헤더의 Access-Control-Allow-Origin값을 확인한 후 클라이언트의 도메인을 포함하고 있으면 응답을 클라이언트로 전송하고, 포함하고 있지 않으면 에러 메세지를 보낸다.
가장 흔하게 사용되는 방식이다. 브라우저는 서버에 요청을 예비 요청, 본 요청 두 번 보낸다. 예비 요청 과정에서 클라이언트가 리소스에 접근할 권한이 있는지를 확인하고, 본 요청에서 일반적인 API 통신처럼 리소스 요청을 하고 응답을 받는다.
💁♀️과정 정리
1. 클라이언트가 요청 API를 브라우저에 전송한다.
2. 예비 요청: 브라우저는 OPTIONS 메서드로 서버에 예비 요청을 전송해 본 요청을 보내도 될지 확인한다.
3. 예비 응답: 서버는 Access-Control-Allow-Origin으로 허용하는 도메인과 허용하는 메서드, 헤더 정보를 헤더에 담아 응답한다.
4. 본 요청: 브라우저는 서버의 응답과 클라이언트의 요청을 비교해 요청이 서버의 조건에 부합하면 요청을 서버에 전송한다.
4-1. 에러 : 서버가 제시한 조건에 클라이언트의 요청이 부합하지 않으면 에러 메세지가 발생한다.
5. 본 응답: 서버가 본 요청에 대한 응답을 전송한다.
6. 서버의 응답이 클라이언트에 전송된다.
클라이언트와 서버단을 모두 내가 관리한다면 서버단에서 Access-Control-Allow-Origin을 헤더에 설정하면 된다. Access-Control-Allow-Origin의 값에 정확한 도메인 주소를 명시하면 무분별하게 다른 도메인에서 나의 서버에서 리소스를 가져가는 일을 막을 수도 있다.
하지만, 외부API를 사용하는 경우에는 헤더를 컨트롤 할 수 없다. 이런 경우에 사용하는 방법이 Proxy server인데, 프록시 서버는 서버와 서버 사이에 위치해 특정 작업을 대신 해주는 서버를 말한다. Cors처리는 브라우저에서 이루어지므로 브라우저와 서버 사이에 프록시 서버를 위치시켜 서버의 응답 API에 Access-Control-Allow-Origin을 붙여 웹 브라우저에 전송시켜주면 된다.
프록시를 써야할경우 https://cors.sh 를 사용하는것도 추천드립니다.