CORS

lim1313·2021년 9월 8일
0

TILPLUS

목록 보기
19/40

CORS

🌈 CORS 정리 블로그1
🌈 CORS 정리 블로그2
🌈 CORS 정리 블로그3

프론트 엔드에서 다른 Origin 의 api 서버로 요청을 보내면 문제가 발생하게 된다. 이 문제를 CORS 문제라고 부른다.

여기서 말하는 Origin 이란, 아래의 세 가지 요소를 조합한 것을 말한다.

  • URL 스키마 (http, https)
  • hostname (localhost, naver.com 등..)
  • 포트 (80 , 3000 , 8080 등..)

브라우저에서는 같은 Origin이 아니라면 요청을 막아버리는 선택을 했던 것이고, 이것이 SOP (Same Origin Policy) 정책이다.

하지만, 너무 수요가 많았기 때문에 공식적으로 특정한 제약조건 속에서 cross-origin 요청을 허용하도록 나온 정책이 CORS 이다.


CORS 동작방식

기본적으로 브라우저에서 다른 출처의 자원을 요청할 때 HTTP 프로토콜을 사용하여 요청을 보내는데, 이 때 브라우저는 요청 헤더에 Origin 이라는 필드에 현재 요청을 보내는 출처를 담아 보낸다.

이 후 서버에서 요청을 받고 응답을 할 때 응답 헤더의 Access-Control-Allow-Origin 라는 필드에 요청한 자원에 접근하는 것이 허용된 출처를 담아 응답한다. 그러면 브라우저에서 응답을 받고, 요청 시에 보냈던 Origin 과 응답 받은 Access-Control-Allow-Origin 을 비교하여 응답의 유효성을 판단한다.

CORS 동작 방식에 대해 세 가지 시나리오를 설명한다.

  1. Simple Request (단순 요청)
  2. Preflight Request (사전 요청)
  3. Credentialed Request (인증 정보를 포함한 요청)

클라이언트 요청 헤더 종류

  • Origin : 요청을 보내는 페이지의 출처(도메인)

  • Access-Control-Request-Method : 실제 요청하려는 메소드를 알려주기 위해 preflight request 시 사용된다.

  • Access-Control-Request-Headers : 마찬가지로 실제 요청에 포함될 있는 헤더를 알려주기 위해 사용된다.

서버 응답 헤더 종류

  • Access-Control-Allow-Origin : 허용할 출처 → 모든 Origin 에 대해 허용하려면 와일드카드 (*) 를 사용한다.

  • Access-Control-Expose-Headers : 브라우저가 접근할 수 있는 헤더를 정의

  • Access-Control-Max-Age : 브라우저에서 preflight request 요청 결과를 캐시할 수 있는 시간(초) 이렇게 퍼미션 정보를 캐싱해두면 브라우저는 일정 기간 동안 preflight request 없이 본 요청을 보낼 수 있다.

  • Access-Control-Allow-Credentials : 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 true. true를 응답 받은 클라이언트는 실제 요청 시 서버에서 정의된 규격의 인증 값이 담긴 쿠키를 같이 보내야 한다.

  • Access-Control-Allow-Methods : 요청을 허용하는 메소드. 기본값은 GET, POST이며 preflight request 에 대한 응답으로 사용되고, 클라이언트에서의 요청이 이 헤더에 포함되는 메서드인 경우 실제 요청을 보낸다.

  • Access-Control-Allow-Headers : 실제 요청 시 사용할 수 있는 헤더

const defaultCorsHeader = {
  'Access-Control-Allow-Origin': 'http://localhost:5000',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Accept',
  'Access-Control-Max-Age': 10,
};

simple Request

Simple Request 는 바로 본 요청을 서버에 보낸 후, 서버의 응답 헤더에 Access-Control-Allow-Origin 과 같은 값을 보내주면 그 때 브라우저가 CORS 정책의 위반 여부를 검사하는 방식이다. 만약 검사를 했을 때 정책을 위반하는 경우라면 서버로부터 받은 응답을 브라우저가 사용하지 않고 버리게 된다.

Preflight Request

Simple Request 의 조건에 만족하지 않는 경우에는 Preflight Request 방식으로 진행이 되는데, 이 방식은 Simple Request 처럼 바로 본 요청을 보내지 않고 먼저 Preflight Request 라고 하는 예비 요청을 먼저 보내게 된다.

CORS, simple request, preflight request

자바스크립트에서 fetch API 를 사용하면 먼저 Preflight Request 을 보내는데, OPTIONS 라는 HTTP 메서드를 사용한다. 이 때, 헤더에 본 요청에서 어떤 메서드를 사용하고, 어떤 헤더를 사용할 것인지에 대한 정보를 담아 예비 요청을 보내면 서버는 어떤 메서드를 허용하고, 어떤 헤더를 허용하는지 정보를 담아 응답한다.

브라우저는 사용할 메서드와 헤더가 허용되는지 응답 받은 정보와 비교하여 본 요청을 보낼지 판단하고, 문제가 없다면 본 요청을 보내게 된다. 이 후 본 요청이 수행되는 과정은 위의 Simple Request 와 동일하게 진행된다.

 if (request.method === 'OPTIONS') {
    response.writeHead(200, defaultCorsHeader);
    response.end();
  } 

예시로 보기

  1. cross-origin 요청이 발생하고 있다.
  2. Content-Type이 application/json이기 때문에, Preflight Request를 보내는데, options라는 HTTP 메서드를 사용한다.

  1. 'Access-Control-Allow-Origin'에서 허용되는 origin이 아니기 때문에, 아래와 같은 응답을 받고 CORS error가 된다.


express에서 간단한 CORS 사용

아래와 같이 간단하게 사용가능하다.

설치
npm install cors

import express from 'express';
import cors from 'cors';

const app = express();

//app.use(cors()) 

app.use(
  cors({
    origin: ['http://127.0.0.1:5500/'],
    optionsSuccessStatus: 200,
    credentials: true, // === Access-Control-Allow-Credentials : true
  })
);

모든 요청에 대해 CORS 허용

app.use(cors()) 

특정 요청에 대해 CORS 허용

app.get('/products/:id', cors(), function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for a Single Route'})
})

더 자세한 정보는 아래 블로그 참고

🌈 CORS 정리 블로그

profile
start coding

0개의 댓글