CORS에 대하여

GOTAEUK·2022년 3월 2일
0
post-thumbnail

CORS란 Cross-Origin Resource Sharing의 약자로 다른 출처에 대한 resource를 공유하는 것을 말한다. 즉, 어떤 출처에서 다른 출처의 resource 접근 권한을 부여하는 것이다. 외부 API를 사용하는 경우에 종종 CORS 오류를 확인할 수 있다. 굉장히 화가 나지만 사실 알고 보면 CORS는 고마운 녀석이 될 수도 있다. 우선 출처의 개념부터 알아보자.


🔎출처(Origin)

URL은 여러가지 구성요소를 가지고 있는데 지금부터 하나의 예시 URL을 뜯어가며 어떻게 구성되어 있는 지 살펴볼 것이다.

예) http://example.com:80/business/mart/item?category=14&id=2965

  • 스킴(Scheme): 프로토콜 이름
  • 호스트(Host): 특정 서버
  • 포트 번호(Port):컴퓨터에서 실행되고 있는 수많은 프로세스들의 주소 (HTTP:80, HTTPS:443)
  • 경로(Path): 원하는 자원이 있는 위치
  • 쿼리(Query): 서버에 요청할 때 원하는 것을 상세하게 표현하기 위해 사용

두 URL을 비교하였을 때 스킴, 호스트, 포트번호가 동일해야 같은 출처라고 할 수 있다. 만약 스킴, 호스트, 포트번호 중 하나라도 다르다면 동일 출처가 아니다.


🔎 SOP (Same-Origin Policy)

만약 다른 출처의 자원 공유를 무작정 허용한다면 CSRF나 XSS같은 방법으로 웹사이트가 공격받을 수 있다. 그래서 다른 출처의 자원을 사용하는 것을 막는 정책이 필요한데 이것이 SOP이다. 즉, SOP는 다른 출처(교차 출처)에서 가져오는 resource들의 상호작용하는 것을 제한하는 것이다. 그러나 이러한 정책은 외부 API를 사용해야 하는 경우에 큰 장애물이 된다. 그래서 CORS라는 정책을 사용함으로 이런 불편함을 해결한다.


🔎 CORS (Cross-origin resource sharing)

이름에서도 알 수 있듯이 CORS는 교차 출처 자원 공유 정책이다. SOP의 문제점을 해결하기 위해 탄생한 정책이라고 볼 수 있다. CORS의 동작 방식은 단순하다. 그러나 여러가지 시나리오가 있기 때문에 먼저 기본적인 동작 원리부터 이해해야 한다.

기본적으로 클라이언트에서 서버로 resource를 요청할 때 요청 헤더 Origin 값을 포함한다. 이후 서버가 요청에 대해 응답할 때 응답 헤더의 Access-Control-Allow-Origin 값과 Origin값을 비교하여 유효한 경우에만 리소스를 공유할 수 있게 하는 기술이다. 요청헤더의 origin은 요청을 보낸 출처를 나타내는 것이고, 응답 헤더의 Access-Control-Allow-Origin은 resource 공유를 허용하는 출처들을 나타낸 것이다.

동작 방식

1. Preflight Request

요청을 보낼 때 총 2번의 요청을 보내 유저 데이터의 영향이 가는 것을 방지함으로 안전성을 보장하는 방식이다. 사전 요청은 OPTIONS 메소드를 사용해 다른 출처의 리소스 요청이 가능한지 확인하는 요청이다. 만약 가능하다면 두번째 요청인 실제 요청을 보낸다.

사전 요청은 다음과 같이 origin , Access-Control-Request-Method, Access-Control-Request-Headers 등이 포함되는데 다음을 의미한다.

  • Preflight Request
origin:요청출처
Acces-Control-Request-Method: 실제 요청의 메소드
Access-Control-Request-Headers: 실제 요청의 추가헤더
  • Preflight Response
Access-Control-Allow-Origin: 서버 측 허가 출처
Access-Control-Allow-Methods: 서버 측 허가 메소드
Access-Control-Allow-Headers: 서버 측 허가 헤더
Access-Control-Allow-Max-Age: 응답 캐시 기간

2. Simple Request

단순 요청은 사전 요청 없이 바로 요청을 보내는 것이다. 사전 요청을 보내지 않기 때문에 Preflight Request보다는 단순하고 빠르지만 기존에 가지고 있던 데이터가 영향을 받을 수 있다는 단점이 있다.

다음 조건을 모두 만족해야 한다.

  • 메서드는 GET POST HEAD 중 하나
  • 헤더는 Accept, Accept-Language, Content-Language, Content-Type 만 허용
  • Content-Type 헤더는 다음의 값들만 허용
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

3. Credentialed Request

이 방법은 다른 출처간 통신에서 보안을 강화하는 방법으로 credentials 옵션을 변경함으로 요청을 보낼 때 쿠키, 인증정보 등을 포함시킬 수 있다.

옵션은 세가지가 존재한다.

  • omit : 절대로 cookie 들을 전송하거나 받지 않는다.
  • same-origin : 동일 출처(same origin)이라면, user credentials (cookies, basic http auth 등..)을 전송한다. (default 값)
  • include : cross-origin 호출이라 할지라도 언제나 user credentials (cookies, basic http auth 등..)을 전송한다.

🔎 CORS 에러 해결 방법

백엔드에서 CORS를 해결하는 방법으로는 단순히 Access-Control-Allow-Origin를 추가하여 서버 측 응답에서 접근 권한을 주는 것이다. 그러나 내 서버가 아닐 경우 컨트롤할 수 없기 때문에 프론트엔드에서 해결하기 위한 방법이 필요하다.

CORS는 브라우저에 관련된 정책이기 때문에 서버간 통신을 할 때에는 해당 정책이 적용되지 않는다. 이 점을 이용하여 프론트엔드에서 CORS 에러를 해결할 수 있다. 외부 서버에 직접 접근하는 것이 아니라 프록시 서버를 두고 간접적으로 통신한다. 프록시 서버는 클라이언트와 서버 사이에서 정보교환을 도와주는 서버이다. 프록시 서버가 실제 서버에 요청을 보내서 받아온 다음 Access-Control-Allow-Origin설정을 적절히 하여 클라이언트에게 돌려주는 방법이다.


출처 및 참고

profile
한걸음씩

0개의 댓글