본문으로 건너뛰기

CORS란 무엇인가

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행한다.

교차 출처 요청의 예시: https://domain-a.com의 프론트엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을 요청하는 경우.

보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한한다. 예를 들어, XMLHttpRequest와 Fetch API는 동일 출처 정책을 따른다. 즉, 이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.


CORS 체제는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원한다. 최신 브라우저는 XMLHttpRequest 또는 Fetch와 같은 API에서 CORS를 사용하여 교차 출처 HTTP 요청의 위험을 완화합니다.

최신 브라우저는 헤더와 정책 집행을 포함한 클라이언트 측 교차 출처 공유를 처리합니다. 그러나 CORS 표준에 맞춘다는 것은 서버에서도 새로운 요청과 응답 헤더를 처리해야 한다는 것입니다.

교차 출처 리소스 공유 표준은 웹 브라우저에서 해당 정보를 읽는 것이 허용된 출처를 서버에서 설명할 수 있는 새로운 HTTP 헤더를 추가함으로써 동작한다. 추가적으로, 서버 데이터에 부수 효과(side effect)를 일으킬 수 있는 HTTP 요청 메서드(GET을 제외한 HTTP 메서드)에 대해, CORS 명세는 브라우저가 요청을 OPTIONS 메서드로 preflight하여 지원하는 메서드를 요청하고, 서버의 "허가"가 떨어지면 실제 요청을 보내도록 요구하고 있습니다. 또한 서버는 클라이언트에게 요청에 "인증정보"(쿠키, HTTP 인증)를 함께 보내야 한다고 알려줄 수도 있습니다.

CORS 실패는 오류의 원인이지만, 보안상의 이유로 JavaScript에서는 오류의 상세 정보에 접근할 수 없으며, 알 수 있는 것은 오류가 발생했다는 사실 뿐입니다. 정확히 어떤 것이 실패했는지 알아내려면 브라우저의 콘솔을 봐야 합니다.

Same-Origin Policy

원칙적으로 브라우저에서는 현재 애플리케이션과 다른 출처에 있는 리소스에 접근이 제한된다.

  • 자신과 동일한 출처(프로토콜 + 도메인 + 포트)의 리소스만 불러올 수 있다.
  • 리소스가 자신의 출처와 다를 때 Cross-Origin HTTP 요청을 실행한다.
  • 해당 출처에서 올바른 CORS 헤더가 포함한 응답을 반환해야 리소스를 불러올 수 있다.

응답에 대한 CORS 에러는 서버가 아닌 브라우저의 스펙이다.

  • 서버가 성공적으로 리소스를 응답해도 브라우저에서 무시하는 것이다.
  • 브라우저는 스크립트에서 시작한 Cross-Origin HTTP 요청을 제한한다.
  • 잠재적으로 해로운 문서를 분리해 공격받을 수 있는 경로를 줄이려는 보안 상의 이유가 있다.

XMLHttpRequest, Fetch API 모두 이 정책을 따르고 있다.

CORS는 HTTP 헤더를 통해 이 접근을 허용하는 체제이다. 간단하게는 응답의 Access-Control-Allow-Origin 헤더와 자신의 출처가 같다면 유효하고 안전한 응답이라고 판단되어 리소스에 접근할 수 있다.

동작 방식

  1. Access-Control-Allow-Origin
  • 서버 측에서 해당 정보를 읽는 것이 허용된 출처이다.
  • 이 헤더에 담긴 출처와 브라우저 측의 Origin이 같아야 한다.
  • Access-Control-Allow- prefix를 가진 HTTP 헤더들은 이 출처에 대한 정보를 담고 있다.
  1. Preflight
  • preflight 요청은 OPTIONS 메서드를 사용하는 사전 요청이다.
  • 서버 데이터에 부수효과(side effect)를 일으킬 수 있는, GET 이외의 HTTP 메서드를 사용하는 요청은 preflight 처리된다.
    • 이 요청에 대한 서버의 허가가 떨어지면 실제 요청을 보내도록 명세에 요구되어 있다.
  • 실제 요청에서 허용되는 메서드, 헤더에 관한 정보를 Access-Control-Allow-Methods/Headers 헤더에 담아 전달한다.
  1. Access-Control-Allow-Credentials
  • 클라이언트에게 인증 정보를 함께 보내야 한다고 알려주기도 한다.
    • cookies, authorization headers, or TLS client ertificates등이 있다.
  • 서버에 쿠키 등의 인증 정보가 필요한 경우 이 헤더를 true로 설정해주어야 한다.
    • npm cors에서는 { credentials: true } 옵션을 통해 가능하다.

다른 출처와의 통신에서 HTTP 헤더를 사용해 제한된 자원의 접근과 정보 제공이 안전하게 이루어지도록 하는 것이 CORS이다.

() => (req: Request, res: Response, next: NextFunction) => {
  // 1.
  res.append('Access-Control-Allow-Origin', env.CLIENT_PATH);

  // 2.
  res.append('Access-Control-Allow-Credentials', 'true');

  // 3.
  // 본 요청에 사용될 수 있는 메서드와 헤더 정보
  res.append('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
  res.append('Access-Control-Allow-Headers', 'Content-Type, Origin, Cookies');

  // OPTIONS 메서드 요청에 OK 응답 전송
  if (req.method === 'OPTIONS') {
    res.status(OK).send();
    return;
  }

  next();
};

Referecne