참고자료

교차 출처 리소스 공유

  • 브라우저가 자신의 출처가 아닌 것들로 부터 요청을 서버가 허용 해주는 HTTP 해더 메커니즘
  • 즉 클라이언트 쪽에서 서버의 요청을 허용할 것인지를 결정하게 된다

CORS 애러 이유

결론부터 말하면 CORS 정책을 지키지 않은 요청으로 인해서 발생한다
백엔드에서 응답줄 때 Access-Control-Allow-Origin해더를 설정해야 함

동일 출처 정책 (Same-Origin)

웹이 구동중인 서버와 HTTP 요청을 통해 불러오는 리소스가 서로 동일한 서버 여야 하는 경우
즉 요청이 내 서버에서 일어난거 아니면 오류 내뿜게 되는

  • 동일 출처의 조건은 HTTP/HTTPS, 호스트, 포트 까지 모두 동일한것을 의미
  • 브라우저의 JS 의 fetchXMLHttpRequest는 기본적으로 해당 정책을 준수 한다
  • 하지만 당연하게도 웹에선 필히 외부 요청을 통해 리소스를 가져올 수 있어야한다
  • 다른 출처 리소스를 불러올때는 반드시 CORS 정책을 지켜서 요청을 보내야 한다

어떤 것들이 해당하는가

  • 브라우저의 JS 의 fetchXMLHttpRequest
  • 웹 폰트 등등

설명

  • Node.js 의 fetch 나 기타 다른 언어들의 HTTP Reqests 에는 해당 되지 않는다
  • 이런 조건으로 서버 쪽에서는 다른 웹 서비스가 내 REST API를 이용 할 수 있도록 설정 하거나 제한 할 수 있다는 이점도 가진다
    • 그러나 CORS는 웹 브라우저 엔진에서만 작동하는거라 어떠한 불특정 다수의 DDOS 공격을 막거나 하는것은 불가하다
    • 왜냐면 그냥 브라우저가 아닌 상황에서의 HTTP Reqests애서는 CORS 가 의미 없기 때문

이렇게 해둔 이유?

  • 만약 아무렇게나 요청을 할 수 있다라고 가정하면
  • 피싱사이트를 개설한 다음 네이버에 요청을 한다고 가정한다
  • 그럼 네이버에 POST 요청을 보내서 브라우저의 저장된 쿠키로 로그인 한다던가 하는게 가능하지 않겠나?
  • 브라우저가 아닌 환경에서는 쿠키를 얻는것이 쉽지 않기에 상관 없지만 브라우저는 아니기 때문에

CORS 정책

요청/응답 시 저정된 특수 해더를 붙어야 한다

과정

  • 브라우저측 요청 (Fetch() 사용)
    GET /resources/public-data/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Connection: keep-alive
    Origin: https://foo.example
    • 여기서 핵심은 Origin, 현재 요청의 원본 주소를 가르킨다
  • 서버 측 응답
    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 00:23:53 GMT
    Server: Apache/2
    Access-Control-Allow-Origin: *
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: application/xml
    • 여기서 핵심은 Access-Control-Allow-Origin, 해당 응답의 접근 가능한 주소 목록을 나타낸다
    • * 이면 모든 것들 허용

설명

  • Fetch 함수에서 자동으로 Origin해더를 붙여 원본 주소를 포함한 정보를 서버에 요청을 보낸다
  • 서버 쪽에서 응답을 받으면 Access-Control-Allow-Origin 의 자신의 도메인(ip) 정보가 있는지 파악한다
  • 없는 경우 해당 리소스의 접근 권한이 없다 판단하여 CORS 애러를 내뿜는다

CORS 해더

클라이언트 요청

API 가 자동으로 설정해줌

  • Origin: IP | Domain:
    • 클라이언트 원본 주소
  • Access-Control-Request-Method:
    • 어떤 메소드 인지
  • Access-Control-Request-Headers:
    • 어떤 해더에 접근하려는 건지

서버 측 응답

  • Access-Control-Allow-Origin: [IP | Domain | *]:
    • 해당 호스트의 리소스 접근을 허용하는
    • CORS 의 핵심
  • Access-Control-Expose-Headers: [Heders...]:
    • 접근가능한 해더 목록 노출
  • Access-Control-Allow-Methods: [HTTP Methods...]:
    • 허용하는 HTTP Method
  • Access-Control-Max-Age: Mills:
    • 응답 캐싱 시간
    • Preflight의 응답을 케싱 하려면 설정 필요
  • Access-Control-Allow-Credentials: boolen:
    • 아래 Credentialed Request 를 사용할 경우 ture로 설정

예비 요청 (Preflight)

브라우저가 요청 보낼 때 한번에 바로 보내지 않고 먼저 예비 요청을 하는 과정

  • Preflight 는 OPTIONS 메소드를 사용하여 요청한다
  • 해당 요청으로 서버가 지원하는 Access-Control-Allow-Origin, Access-Control-Allow-Methods 정보들을 안전확보 후 본 요청을 보내게
  • 하지만 여기서 문제는 응답 시간인데 결국 2번 요청을 보내는 거니까 해결을 위해 Access-Control-Max-Age 해더를 서버측에 설정하면 Preflight 응답을 케싱 할 수 있다

단순요청 (Simple Request)

위 Prefilght 과정 없이 다이렉트로 요청하는
아래 조건을 만족시켜면 Preflight 과정 없이 진행된다

  • 가능 조건:
    • 메소드
      • GET, HEAD, POST
    • 해더:
      • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width
    • Content-Type:
      • application/x-www-form-urlencoded multipart/form-data, text/plain

인증된 요청 (Credentialed Request)

세션id 가 저장되어있는 쿠키, Authorization 해더 토큰값 같은 자격 정보를 보낼 때 사용하는 방식

  • 단순요청 조건을 만족하면 단순요청 으로 처리되고 아니면 예비요청 으로 처리됨

제약 사항

해당 요청에서 서버측 해더에 이것들 지키지 않으면 CORS오류 뜸

  • Access-Control-Allow-Credentials를 true로 설정
  • Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers 에서 * 사용불가

API 설정

  • Fetch
    • credentials 옵션을 include로 설정하기
      fetch("https://example.com:1234/users/login", {
      	method: "POST",
      	credentials: "include", // 자격 정보를 담겠다는 의미
      })