CORS(Cross-Origin Resource Sharing)

SNSTalk 를 개발하면서 생긴 문제에 대해 정리해 보려고 한다. 그 중 하나인 웹 개발을 하면서 누구나 한번쯤 겪어봤던 CORS 문제이다.

api 통신을 위해 클라이언트 쪽에 비동기통신 라이브러리 axios 를 활용하여 서버쪽에 요청을 보냈다.

1. CORS

CORS는 Cross-Origin Resource Sharing의 줄임말로, 직역하면 교차 출처 리소스 공유이다.
먼저 출처(Origin)가 뭔지 확인해보면..

출처(Origin)란?

하나의 URL을 보더라도 여러개의 구성요소로 이루어져 있다. 만약 https://naver.com:5000과 같이 같은 출처에 포트 번호가 명시적으로 포함되어 있다면 이 포트 번호까지 모두 일치해야 같은 출처라고 인정된다

우리가 CORS 정책을 위반하는 리소스 요청을 하더라도 해당 서버가 같은 출처에서 보낸 요청만 받겠다는 로직을 가지고 있는 경우가 아니라면 서버는 정상적으로 응답을 하고, 이후 브라우저가 이 응답을 분석해서 CORS 정책 위반이라고 판단되면 그 응답을 사용하지 않고 그냥 버리는 순서인 것이다.

즉, CORS는 브라우저의 구현 스펙에 포함되는 정책이기 때문에, 브라우저를 통하지 않고 서버 간 통신을 할 때는 이 정책이 적용되지 않는다. 또한 CORS 정책을 위반하는 리소스 요청 때문에 에러가 발생했다고 해도 서버 쪽 로그에는 정상적으로 응답을 했다는 로그만 남기 때문에, CORS가 돌아가는 방식을 정확히 모르면 에러 트레이싱에 난항을 겪을 수도 있다.

2. CORS의 동작

3. CORS해결방법

Access-Control-Allow-Origin 세팅하기

CORS 정책 위반으로 인한 문제를 해결하는 가장 대표적인 방법은, 그냥 정석대로 서버에서 Access-Control-Allow-Origin 헤더에 알맞은 값을 세팅해주는 것이다.

사실 CORS를 가장 많이 마주치는 환경은 바로 로컬에서 프론트엔드 어플리케이션을 개발하는 경우라고 해도 과언이 아니다. 백엔드에는 이미 Access-Control-Allow-Origin 헤더가 세팅되어있겠지만, 이 중요한 헤더에다가 http://localhost:3000 같은 범용적인 출처를 넣어주는 경우는 드물기 때문이다.

Node로 예시를 들자면 미들웨어에 다음과 같이 설정해 줄 수 있다.

app.use(
  cors({
    origin: '*'
  }),
);

이때 와일드카드인 *을 사용하여 이 헤더를 세팅하게 되면 모든 출처에서 오는 요청을 받아먹겠다는 의미이므로 당장은 편할 수 있겠지만 보안에 이슈가 생길 수 있다. 일단 저렇게 작성하고 요청을 보내면 다음과 같은 오류가 나온다.

로그인 후 포스트를 작성하려고 하는데 로그인을 하지 않았다고 서버에서 에러를 보낸것이다. 이유는 도메인URL이 다르면 cors설정을 해 줘도 세션id가 포함된 쿠키가 전달되지 않는다. 그래서 아래와 같이 작성 후 확인해보면..

app.use(
  cors({
    origin: '*',
    credentials: true, //쿠키도 전달
  }),
);

위와 같은 오류가 한번 더 발생한다. credentials을 넣어줌으로써 보안이 더 중요해 졌기 때문에 origins에 정확한 도메인주소를 적어줘야 한다.

app.use(
  cors({
    origin: 'http://localhost:3060',
    credentials: true, //쿠키도 전달
  }),
);

Webpack Dev Server로 리버스 프록싱하기

프론트엔드 개발자는 대부분 웹팩과 webpack-dev-server를 사용하여 자신의 머신에 개발 환경을 구축하게 되는데, 이 라이브러리가 제공하는 프록시 기능을 사용하면 아주 편하게 CORS 정책을 우회할 수 있다.

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.evan.com',
        changeOrigin: true,
        pathRewrite: { '^/api': '' },
      },
    }
  }
}

이렇게 설정을 해놓으면 로컬 환경에서 /api로 시작하는 URL로 보내는 요청에 대해 브라우저는 localhost:8000/api로 요청을 보낸 것으로 알고 있지만, 사실 뒤에서 웹팩이 https://api.evan.com 으로 요청을 프록싱해주기 때문에 마치 CORS 정책을 지킨 것처럼 브라우저를 속이면서도 우리는 원하는 서버와 자유롭게 통신을 할 수 있다. 즉, 프록싱을 통해 CORS 정책을 우회할 수 있는 것이다.

좋은 웹페이지 즐겨찾기