CORS


Cross-Origin Resource Sharing

동일 출처 정책 (SOP)

  • 브라우저에서 서버에 요청을 보낼 때, 출처가 같지 않으면 차단하는 정책
  • 브라우저에서 서버에 요청을 보낼 때는, 클라이언트의 Origin과 서버의 Origin이 같아야 동일 출처 정책에 의해 차단되지 않음.
  • 이는 백엔드에서 요청을 보낼 때에는 적용되지 않고, 브라우저에서 요청을 보낼 때만 적용된다. 출처 비교와 차단은 브라우저에 구현된 스펙이다. (서버에 구현된 스펙이 아니다)
  • 브라우저는 사용자의 개인정보를 담고있고, 이러한 제약이 없다면 해커가 CSRF(Cross-site request forgery)XSS(Cross-site scripting)등의 방법을 이용하여 개인정보를 가로챌 수 있기 때문이다.
  • [참고] 출처(Origin)

  • 우리가 어떤 사이트에 접속할 때 사용하는 URL은 다음과 같은 구성요소로 이루어져 있다.
  • 여기서 Origin은 Protocol + Host + Port 이다.
  • 따라서 Cross-Origin 이란 다음과 같은 경우를 말한다.
  • [참고] XSS (Cross-Site Scripting)

    [참고] CSRF (Cross-Site Request Forgery)

  • 사이트 간 요청 위조 → 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격
  • 사례: 2008년 옥션 개인정보 유출 사건 (피해 회원 총 1863명)
  • CORS

  • CORS(Cross-Origin Resource Sharing)는 다른 출처의 리소스 공유에 대한 허용/비허용 정책
  • SOP라는 원칙에 대한 예외
  • CORS 정책을 따르면 다른 출처의 리소스라도 서버와 브라우저 간에 주고받을 수 있게 된다.
  • CORS의 기본 동작

  • 브라우저에서 서버에 요청을 보낼 때 현재 브라우저의 출처(Origin)를 요청 헤더에 담아 보낸다.
  • 서버는 해당 요청에 대한 응답 헤더에 Access-Control-Allow-Origin이라는 필드를 추가하여 해당 필드에 이 리소스를 접근하는 것이 허용된 출처를 담아 보낸다. 이는 서버에서 미리 설정되어야 할 부분이다.
  • 브라우저에서 현재 본인의 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교하여 만약 유효하지 않다면 해당 응답을 차단하고 CORS 에러를 띄운다. 그게 아니라 위 사진처럼 두 Origin이 같다면 CORS 정책에 따른 것으로, 해당 응답을 가져온다.
  • CORS 작동 방식의 3가지 시나리오

    예비 요청 (Preflight Request)

  • 사실 브라우저는 요청을 보낼 때 한번에 바로 보내지 않고, 먼저 예비 요청을 보내 서버와 잘 통신되는지 확인 후 본 요청을 보낸다.
  • 예비 요청은 본 요청 전에 브라우저가 스스로 안전한 요청인지 확인하기 위해 진행된다.
  • 여기서는 OPTIONS라는 메소드를 사용하여 요청이 일어난다.
  • 예비요청에서도 본 요청에서와 같이 요청 헤더의 Origin과 응답 헤더의 Access-Control-Allow-Origin의 값을 비교하여 CORS 정책에 따르는지 확인하게 된다.
  • 예비 요청은 보안을 강화하는 목적의 취지는 좋지만, 결국 실제 요청에 걸리는 시간이 늘어나게 되어 성능 저하로 이어질 수 있다.
  • 단순 요청 (Simple Request)

  • 단순 요청은 예비 요청을 생략하고 바로 서버에 본 요청을 보내는 방식이다.
  • 특정한 조건이 만족되는 경우에만 예비 요청을 생략할 수 있다.
  • 대부분의 HTTP 요청은 application/json으로 통신하기 때문에 3번에서 위반되는 경우가 많아 대부분의 요청은 예비 요청으로 이루어진다고 볼 수 있다.
  • 인증된 요청 (Credentialed Request)

  • 인증된 요청은 클라이언트에서 서버에게 자격 인증 정보(Credential)를 실어 요청할 때 사용되는 요청이다.
  • 여기서 자격 인증 정보란 세션 ID가 저장되어있는 쿠키(Cookie) 혹은 Authorization 헤더에 설정하는 토큰 값 등을 말한다.
  • 클라이언트에서 다음과 같이 요청을 보내면 인증 정보를 보내도록 설정할 수 있다. 이러한 설정을 해주지 않으면 쿠키 등의 인증 정보는 절대로 자동으로 서버에 전송되지 않는다.
  • fetch("https://example.com:1234/users/login", {
    method: "POST",
    credentials: "include", // 클라이언트와 서버가 통신할때 쿠키와 같은 인증 정보 값을 공유하겠다는 설정
    body: JSON.stringify({
    userId: 1,
    }),
    })
  • 이에 대한 응답으로 서버는 몇 가지를 지켜주어야 한다.
  • 이를 지키지 않은 응답이 오면 브라우저는 CORS 정책에 의해 응답을 거부한다.
  • CORS 오류를 피하는 방법

    서버에서 CORS 설정하기

    Express.js

    npm i cors
    const express = require('express')
    const cors = require('cors');
    const app = express();
    app.use(cors({
    origin: 'https://domain.com',
    }));

    프록시 서버 사용하기

  • Proxy의 사전적 의미는 대리인
  • 프록시 서버 구현 방식
  • React 개발 환경에서 proxy 옵션 추가
  • 백엔드에서 요청하기

  • 서버가 내가 관리할 수 있는 서버가 아닌 경우
  • 참고

  • https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy
  • https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
  • https://evan-moon.github.io/2020/05/21/about-cors/
  • https://inpa.tistory.com/entry/WEB-📚-CORS-💯-정리-해결-방법-👏