article thumbnail image
Published 2022. 11. 18. 17:56

CORS 란?

CORS 는 Cross Origin Resource Sharing의 약자입니다.

Cross : 교차, Origin : 출처, Resource : 자원, Sharing : 공유

말 그대로 서로 다른 출처끼리 자원을 공유하겠다는 뜻입니다.

(출처: MDN 공식 문서)

 

좌측의 웹 페이지는 domain-a.com 에 접속하면 볼 수 있는 웹 페이지입니다.

domain-a.com 에 접속하면 웹 페이지를 렌더링하기 위해서 총 5개의 API 요청이 발생하고 있습니다.

이 중 셋은 Same Origin 이고 둘은 Cross Origin 입니다.

상단의 파란색 네모 박스 안에 있는 API 는 Same Origin 입니다.

domain-a.com 에서 웹 서버 domain-a.com 으로 요청을 보냈기 때문에 Same Origin 입니다.

반면 하단의 빨간색 네모 박스 안에 있는 API 는 Cross Origin 입니다.

domain-a.com 에서 웹서버 domain-b.com 으로 요청을 보냈기 때문입니다.

 

서버는 허용되지 않은 Origin 으로부터 요청을 받으면 요청을 거부하기 때문에 하단의 빨간색 네모 박스에 있는 컨텐츠는 서버로부터 제공받지 못지 못합니다.

 

정리하면,

요청을 보내는 Client 와 요청을 받는 Server 의 도메인이 다르면 Cross Origin 이라 부르고 Client 의 요청은 거부됩니다. 

CORS 는 언제 발생하는가?

CORS 는 Cross(서로 다른) Origin 끼리 통신할 때 발생합니다.

참고) Origin 이란?

예시 URL 을 보며 Origin 에 대해 알아보겠습니다.

https://developer.mozilla.org:443/ko/docs/Web/HTTP/CORS

- https : 프로토콜

- developer.mozilla.org : 호스트

- :443 : 포트

 

Origin 은 프로토콜, 호스트, 포트를 포함하는 개념입니다.

Origin 은 셋 중 하나만 달라져도 CORS 가 발생합니다.

 

몇 가지 예시를 통해 CORS 여부를 확인해보겠습니다.

예시 CORS 여부
http://google.com -> https://google.com  O, 프로토콜이 다르기 때문
https://api.google.com -> https://google.com  O, 호스트가 다르기 때문
https://google.com:8080 -> https://google.com  O, 포트가 다르기 때문
https://google.com/console -> https://google.com  X
https://google.com/console?id=1 -> https://google.com  X

그렇다면 Cross(서로 다른) Origin 간의 통신은 절대 불가능한 걸까요?

=> Cross(서로 다른) Origin 간의 통신 가능합니다!

서로 다른 Origin 간의 통신이 필요할 수도 있는데, 그땐 어떻게 해야 할까요?

=> HTTP Header 를 조작하면 됩니다. 구체적으로는 HTTP Header 에 요청을 보내는 Origin 에 대한 정보를 추가하면 됩니다.

CORS 를 허용하는 방법

CORS 를 허용하는 방법은 Preflight, Simple Request 가 있습니다.

Preflight 란?

Preflight 는 브라우저가 main(본) 요청을 보내기 전에 보내는 사전 요청입니다.

사전 요청은 API 요청을 보낼 때마다 매번 보내는 걸까요?

=> 그렇지 않습니다.

Simple Request

main(본) 요청이 Simple Request 의 조건을 만족한다면 Preflight 를 보낼 필요가 없습니다.

 

Simple Request 의 조건은 다음과 같습니다.

- HTTP METHOD 가 GET, HEAD, POST 중 하나일 때

- Request 객체 생성 시 자동으로 생성되는 헤더들(Accept, Accept-Language, Content-Language, Content-Type) 외의 다른 HTTP Header 가 조작되지 않은 요청

- Content-Type 의 값이 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나일 때

- XHR 객체로 API 요청을 보낼 때 xhr.upload.addEventListener() 를 호출하지 않은 요청

- API 요청을 보낼 때 ReadableStream 객체가 사용되지 않은 요청

Preflight 의 역할

Preflight 는 실제 요청을 보내기 전, 실제 요청이 안전한지 판단하기 위해 보내는 사전 요청입니다.

Preflight 는 어떻게 실제 요청의 안전 여부를 판단한다는 걸까요?

=> Preflight 의 Request, Response 객체를 보면 알 수 있습니다.

Preflight Request

Preflight 의 Request 객체에서는 main(본) 요청의 정보들을 Access-Control-Request- 헤더들에 저장합니다.

Preflight Request 의 HTTP METHOD 는 OPTIONS 입니다.

만약 main(본) 요청에서 HTTP 헤더를 조작해 다른 헤더를 추가한다면 Access-Control-Request-Headers에 [추가된 Header 이름] 이 저장됩니다. 이는 새로 추가된 헤더도 허용해 달라는 의미입니다.

Preflight Response

서버에서는 Preflight Request 의 헤더를 기반으로 Preflight Response 를 응답합니다. 구체적으로 말하자면 Access-Controller-Allow- 로 시작하는 헤더를 추가해서 응답합니다.

그런데 이 과정은 서버가 자동으로 해주지 않고 개발자가 직접 설정해줘야 하는 부분입니다.

// 모듈 import
const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors({
  origin: 'http://example.com', // 허용하는 Origin 추가
  methods: ['GET', 'PUT', 'POST'], // 허용하는 Method 추가
  allowedHeaders: "Something", // 허용하는 Header 추가
  credentials: true, // Access-Control-Allow-Credentials CORS header 설정
});

출처

https://evan-moon.github.io/2020/05/21/about-cors/ 

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS 

https://www.npmjs.com/package/cors#configuring-cors 

복사했습니다!