DEV Community

Cover image for How to used CORS?
Heetae Kim
Heetae Kim

Posted on • Edited on

How to used CORS?

Image description

CORS?

웹 애플리케이션에서 HTTP 프로토콜을 통해 데이터를 요청하고 응답을 받는다.
즉, 웹 사이트는 URL이라는 출처를 가지고 요청을 하게 되는데, 동일 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용 하는 것을 제한하는 보안 방식을 SOP(Same Origin Polict)라 한다.

이는 악의를 가진 사용자가 정보를 탈취하거나 잠제적인 악성 문서를 격리하기 위해 브라우저에서 사용되는 방식이다.

그러나 웹 이라는 오픈스페이스 환경에서 다른 출처에 있는 리소스를 사용하는 일이 빈번하게 발생하게 되고 무작정 막을 수 없기 때문에 CORS(Cross Origin Resource Sharing) 라는 보안 방식이 등장하게 되었다.

동일 출처란 두 URL의 프로토콜, 포트(명시한 경우), 호스트가 모두 같은 출처이다.

SOP(Same Origin Policy)

  • 다른 출처의 리소스를 사용하는 것을 제한하는 보안 방식.
  • XMLHttpRequest, Fetch API 처럼 JavaScript로 서로 다른 도메인에 대한 요청은 SOP 정책을 따른다.

CORS(Cross Origin Resource Sharing)

  • 다른 출처의 자원을 공유하는 보안 방식.
  • 교차 출처 리소스 공유(CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 즉, 우리가 가져오는 리소스들이 안전한지 검사하는 관문이다.
  • link, script, img, video, audio, iframe 태그 및 @font-face 처럼 교차 삽입의 경우 CORS 정책을 따른다.

출처를 비교하는 로직은 서버에 구현된 스펙이 아닌 브라우저에 구현된 스펙이다.
Image description

정리하자면 CORS 정책이 적용되는 네트워크 요청의 경우, 네트워크 요청(request)에는 현재 요청을 보내는 사이트의 Origin 헤더가 존재해야 하고, 네트워크 응답(response)에는 그에 상응하는 Access-Control-Allow-Origin 헤더가 존재해야 한다.

결과적으로 요청의 Origin 헤더와 응답의 Access-Control-Allow-Origin 헤더에 명시된 도메인이 일치해야만 네트워크 요청이 정상적으로 마무리되고 우리가 원했던 리소스를 가져올 수 있게 된다. -> CORS 이슈는 SOP에 의해 발생한다.

항상 이론을 이해하면서 고개를 끄덕이지만 실제로 접하면...

Image description

 

CORS 동작에 따른 3가지 시나리오

위에서 설명한 바와 같이 CORS는 다음과 같은 과정을 가진다.

  1. 클라이언트에서 HTTP 프로토콜을 사용하여 요청을 보내게 되는데 이 때 헤더에 Origin 으로 요청의 출처를 담아서 함께 보낸다.

  2. 서버에서 Access-Control-Allow-Origin 에 요청의 출처를 담아 클라이언트로 응답을 보낸다.

  3. 클라이언트에서 응답을 받으면 브라우저가 OriginAccess-Control-Allow-Origin을 비교하여 SOP를 위반했는지 확인한다.

이러한 동작은 아래의 3가지 시나리오에 의해 다시 달라진다.

  • Preflight Request
  • Simple Request
  • Credentialed Request

Preflight Request

브라우저가 예비요청과 본 요청으로 나누어 서버로 전송하게 되는데, 이 예비요청을 Preflight 라고 한다.

Image description

  • 실제 요청이 전송하기 안전한지 확인하기 위해 실제 요청 이전에 수행하는 사전 요청이다.
  • 서버는 응답 헤더에 Access-Control-Allow-Origin 값을 전달하여 브라우저가 SOP 위반 여부를 판단하게 한다.
  • Access-Control-Allow-Origin: * | (origin)
  • OPTIONS 메서드를 사용하여 사전 요청을 보낸다.
  • 일반적으로 CORS가 발생하는 요청이다.

Simple Request

명확한 명칭은 없지만 Preflight Request를 보내지 않고 서버에게 요청을 하는 것을 단순 요청(Simple Request)라고 한다.

하지만 아무 때나 단순 요청을 사용할 수 있는 것은 아니고, 특정 조건을 만족하는 경우에만 예비 요청을 생략할 수 있다. 게다가 이 조건이 조금 까다롭기 때문에 일반적인 방법으로 웹 어플리케이션 아키텍처를 설계하게 되면 거의 충족시키기 어려운 조건들이라 필자도 이런 경우를 거의 경험하지는 못 했다.

Image description

  • 사전 요청을 보내지 않고 바로 서버에 요청을 보낸다.
  • 서버는 응답 헤더에 Access-Control-Allow-Origin 값을 전달하여 브라우저가 SOP 위반 여부를 판단하게 한다.
  • Access-Control-Allow-Origin: * | (origin) | null
  • Access-Control-Allow-Origin: <origin> 인 경우 Vary 속성도 같이 제공해야 한다. MDN 참고

Simple Request는 아래 조건을 전부 만족해야 요청이 가능하다.

  • GET, HEAD, POST 메소드 중 하나를 사용
  • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 를 제외한 헤더를 사용하면 안된다.
  • Content-Type 사용 시 application/x-www-from-urlencoded, multipart/form-data, text/plain 만 허용

Credentialed Request

Credentialed Request은 요청 시 보안을 강화하고 싶을 때 사용하는 방법이다.
일반적으로 XMLHttpRequest, fetch는 별도 옵션 없이 브라우저의 쿠키 정보, 인증과 관련된 헤더를 요청에 넣지 않지만, Credentialed Request를 통해 헤더에 인증과 관련된 정보를 넣을 수 있다.

이때 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션이다.

credentials 옵션 3가지

  • same-origin : 기본값이며, 같은 출처 간 요청에만 인증 정보를 담게 한다.
  • include : 모든 요청에 인증 정보를 담는다.
  • omit : 모든 요청에 인증 정보를 담지 않는다.

same-origin이나 include와 같은 옵션을 사용하여 리소스 요청에 인증 정보가 포함된다면, 이제 브라우저는 다른 출처의 리소스를 요청할 때 단순히 Access-Control-Allow-Origin만 확인하는 것이 아니라 Access-Control-Allow-Credentials: true 를 서버에서 응답 헤더에 포함하여 전달해 주어야 한다.

  • 기존 CORS 방식에서 인증 관련 헤더를 포함할 때 사용하는 요청이다.
  • 요청 헤더에 credentials 옵션을 사용하게 되면 인증 관련된 헤더를 넣을 수 있다.
  • 서버는 응답 헤더에 Access-Control-Allow-Origin : * 값을 사용할 수 없으며, 명시적인 URL 이어야 한다.
  • 서버는 응답 헤더에 반드시 Access-Control-Allow-Credentials : true 가 있어야 클라이언트의 인증 포함 요청에 허용이 가능하다.

ref: https://evan-moon.github.io/2020/05/21/about-cors/
ref: https://beomy.github.io/tech/browser/cors/

Top comments (0)