CORS

·2023년 2월 27일
0

개발 지식

목록 보기
34/96
post-thumbnail

CORS, 교차 출처 자원 공유 방식

CORS, cross-origin-resources-sharing 란 웹 브라우저에 구현된 보안기능으로, 현재 웹 사이트를 띄우고 있는 도메인이 다른 도메인에게 요청을 허가할 수 있도록 설정한다.

CORS의 등장배경?

기본적으로 웹 브라우저는 악의적인 공격을 방지하기 위한 보안 조치로, 다른 도메인에 요청하는 것을 제한한다. 만약 이게 기본적으로 가능하다면, 클라이언트에 저장된 브라우저 데이터를 기반으로 요청을 하여, 개인정보를 탈취하는 등의 다양한 악의적 행위가 가능하기 때문이다.

그런데 우리는 웹 사이트를 만들다보면, API 를 활용하거나, 리소스를 가져오기 위해 다른 도메인에 요청을 보내기도 한다. 이러한 필요성 때문에 어떠한 조건이 충족되면 지정한 도메인의 리소스에 접근할 수 있도록 만들어진 메커니즘이 CORS 이다.

SOP
자바스크립트 엔진 표준 스펙의 보안 규칙으로 하나의 출처(Origin)에서 로드된 자원(문서나 스크립트)이 호스트나 프로토콜, 포트번호가 일치하지 않는 자원과 상호작용 하지 못하도록 요청 발생을 제한하고, **동일 출처(Same Origin)에서만 접근이 가능한 정책이다.

즉, 우리가 흔히 말하는 CORS 에러는 SOP에 의한 경고인 것이고, CORS 는 이러한 동일 출처 제한에서 접근이 허용하도록 해주는 설정인 것이다.**

CORS 이슈? 해결하기

일반적으로 서드 파티 API 를 활용하거나 다른 도메인의 리소스를 사용하는 것은 보통 백앤드에서 담당하여 다루게 된다. 그 이유는 보안, 도메인 설정 등 다양한 이유들이 있겠으나 개인적으로는 비용적인 문제가 크다고 생각한다.

API 생성 회사의 경우, 요청건수, IP 단위로 요금을 책정하는데, 프론트엔드에서 요청하게 되면 해당 페이지가 렌더링 될 때마다 요청을 보내야 하지만, 서버에서 담당하는 경우 트랜지션을 통해 한번에 처리하거나, 중복된 요청을 제어하는 것이 가능하기 때문이다.

💡 물론 요즘은 무료 API을 쓰는 경우도 많고 프론트앤드도 최적화를 위해 캐싱이나 중복요청을 제어하는 방법들도 있어서, 프론트앤드에서 API를 다이렉트로 연결하는 사례도 증가하는 편이다.

그래서인지 대부분의 백앤드 프레임워크들은 CORS 설정을 하는 방법들이 공식문서에 명시되어있다. 모든 서버를 다 써본 것은 아니기에, 명확히 말할 수는 없으나 일반적으로 Allow-Origin 을 통해, 요청이 허가되어야 하는 사이트들을 추가해두면 된다.

package com.ssafy.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
    //cors error
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("[domain1, domain2]")
                //.allowedOriginPatterns("*")
                //.allowCredentials(true)
                .allowedMethods("*")
                .allowedHeaders("*")
                .exposedHeaders("Authorization")
                .allowCredentials(true)
                .maxAge(86400L);
    }
}
const cors = require('cors');

let corsOptions = {
    origin: 'domain1',
    credentials: true
}
app.use(cors(corsOptions));

그 외에도, 프론트엔드의 경우에는 webpack-dev-server-proxy 기능을 이용하여, CORS 를 가능하게 할 수 있다.

webpack-dev-server 의 프록시를 사용하면, 브라우저에서 API 를 요청 할 때 백엔드 서버에 직접적으로 요청을 하지 않고, 현재 개발서버의 주소로 요청을 하게 된다. 해당 요청을 받아 그대로 백엔드 서버로 전달, 백엔드 서버에서 응답한 내용을 다시 브라우저쪽으로 반환한다.

CRA(create-react-app) 로 생성한 프로젝트라면 package.jsonproxy 값을 설정하여 간단하게 webpack-dev-server proxy 기능을 활성화 할 수 있다.

// webpack.config.ts
const config: webpack.Configuration = {
  ...
  devServer: {
    port: 3090, // 클라이언트 포트 번호
    proxy: {
      '/api/': { // /api/로 시작하는 url은 아래의 전체 도메인을 추가하고, 옵션을 적용 
        target: 'http://localhost:3095', // 클라이언트에서 api로 보내는 요청은 주소를 3095로 바꿔서 보내겠다 라는 뜻
        changeOrigin: true, // cross origin 허용 설정
      },
    },
  },
  ...
}

// 비동기 요청 코드
// signUp.ts
// proxy 적용 전 비동기 요청 코드
axios
  .post('http://localhost:3095/api/users', {
    email,
    nickname,
    password,
  })

// proxy 적용 후 비동기 요청 코드
axios
  .post('/api/users', {
    email,
    nickname,
    password,
  })

참고
웹개발 짜증유발자! CORS가 뭔가요?
CORS는 왜 이렇게 우리를 힘들게 하는걸까?
교차 출처 리소스 공유 (CORS) - HTTP | MDN
SOP와 CORS
https://velog.io/@jjhstoday/webpack-proxy를-사용하여-CORS-에러-해결-하기

profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글