CORS 에러를 어떻게 해결할 수 있을까?

Jay·2022년 4월 4일
2
post-thumbnail

스터디에서 CORS에 대해 발표한 내용을 정리한다.
발표 자료 LINK

▪️ Cors의 정의

Cross-Origin-Resource-Sharing

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

출처(Origin)는 크게 Protocol, Host, Port, query string 네 범주로 구분되는데, 이 중에서 Protocol, Host, Port가 일치하면 출처가 같다고 표현한다. 이 중 하나라도 어긋날 경우 Cross-origin으로 간주한다. 주의할 점은 Cors가 브라우저에서 시행하는 정책이라 브라우저마다 기준이 조금씩 다르다는 것인데 일반적으로는 이런 기준을 사용하고 있다.

▪️ Cors의 탄생 배경

Cors를 이해하려면 Cors를 어떤 배경에서 사용하게 되었는지를 이해해야 한다

SOP(Same-Origin-Policy)

SOP는 동일 출처 정책 이라는 의미로 Cors와 마찬가지로 브라우저에서 시행하는 정책이며 동일 출처 간에만 리소스를 공유할 수 있도록 하는 보안 메커니즘이다. Origin의 기준은 Cors처럼 Porotocol, host, port다. SOP는 다른 도메인, 확인되지 않은 도메인에 요청을 보냈다가 보안상 문제가 생길 수 있어 이런 문제를 미연에 방지하기 위해 만들어진 정책이다. 하지만 웹이 점점 발전할수록 도메인간의 통신은 피할 수 없는데, 이를 위해 SOP를 완화해 다른 출처 간에도 통신할 수 있도록 하는 방안중 하나가 Cors다. 위에서 본 에러는 기본적으로 브라우저에는 SOP가 통용되고 있는데, Cors 정책을 사용하기 위한 조건을 만족시키지 못했기 때문에 발생했음을 알 수 있다.

▪️ Cors의 동작 방식

Cors의 동작 방식은 크게 세 가지인데, 조건과 쓰임새에 따라 달리 사용된다. 여기서는 Simple과 Preflight 요청 방식만 기술한다.

Simple Request(단순 요청)

Simple Request는 과정이 단순한 만큼 조건이 까다롭다.

  • HTTP Method: GET, POST, HEAD
  • HEADER: 자동 설정된 헤더 외에 Accept, Accept-Language, Content-Language, Content-Type만 추가 가능
  • Content-type: 헤더의 컨텐트 타입은 application/x-www-form-urlencoded, mulitpart/form-data, text/plain만 가능하다

위 조건을 충족하면 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값을 확인한 후 클라이언트의 도메인을 포함하고 있으면 응답을 클라이언트로 전송하고, 포함하고 있지 않으면 에러 메세지를 보낸다.

Preflight Request(인증된 요청)

가장 흔하게 사용되는 방식이다. 브라우저는 서버에 요청을 예비 요청, 본 요청 두 번 보낸다. 예비 요청 과정에서 클라이언트가 리소스에 접근할 권한이 있는지를 확인하고, 본 요청에서 일반적인 API 통신처럼 리소스 요청을 하고 응답을 받는다.

💁‍♀️과정 정리
1. 클라이언트가 요청 API를 브라우저에 전송한다.
2. 예비 요청: 브라우저는 OPTIONS 메서드로 서버에 예비 요청을 전송해 본 요청을 보내도 될지 확인한다.
3. 예비 응답: 서버는 Access-Control-Allow-Origin으로 허용하는 도메인과 허용하는 메서드, 헤더 정보를 헤더에 담아 응답한다.
4. 본 요청: 브라우저는 서버의 응답과 클라이언트의 요청을 비교해 요청이 서버의 조건에 부합하면 요청을 서버에 전송한다.
4-1. 에러 : 서버가 제시한 조건에 클라이언트의 요청이 부합하지 않으면 에러 메세지가 발생한다.
5. 본 응답: 서버가 본 요청에 대한 응답을 전송한다.
6. 서버의 응답이 클라이언트에 전송된다.

Proxy server

클라이언트와 서버단을 모두 내가 관리한다면 서버단에서 Access-Control-Allow-Origin을 헤더에 설정하면 된다. Access-Control-Allow-Origin의 값에 정확한 도메인 주소를 명시하면 무분별하게 다른 도메인에서 나의 서버에서 리소스를 가져가는 일을 막을 수도 있다.
하지만, 외부API를 사용하는 경우에는 헤더를 컨트롤 할 수 없다. 이런 경우에 사용하는 방법이 Proxy server인데, 프록시 서버는 서버와 서버 사이에 위치해 특정 작업을 대신 해주는 서버를 말한다. Cors처리는 브라우저에서 이루어지므로 브라우저와 서버 사이에 프록시 서버를 위치시켜 서버의 응답 API에 Access-Control-Allow-Origin을 붙여 웹 브라우저에 전송시켜주면 된다.

profile
You're not a computer, you're a tiny stone in a beautiful mosaic

1개의 댓글

comment-user-thumbnail
2022년 9월 27일

프록시를 써야할경우 https://cors.sh 를 사용하는것도 추천드립니다.

답글 달기