All Articles

CORS 복습하기

Prologue:

  • 간만에 서버 만들어서 주소 포트 알려줬고 동작 테스트 시작

    • 네트워크 이슈 -> 네트워크 연결
    • http 이슈 -> nginx port fowarding
    • cert Invaliid -> thisisunsafe
    • CORS 이슈?

      • flask 아예 처음 부터 세팅해서 올렸는데?

        • flask? nginx? front? 돌고 돌다
        • cors 무지함을 깨닫고 찬찬히 살펴봄

CORS

  • 의미

    • 여기를 읽어보면 히스토리부터 자세히 설명이 되어있다.
    • TLDR;

      도메인이나 서브도메인, 프로토콜, 포트가 다른 곳에 요청을 보내는 것을 Cross-Origin Request(크로스 오리진 요청)라고 합니다. 크로스 오리진 요청을 보내려면 리모트 오리진에서 전송받은 특별한 헤더가 필요합니다.

      이러한 정책을 ‘CORS(Cross-Origin Resource Sharing, 크로스 오리진 리소스 공유)‘라고 부릅니다.

  • 해결찾아가는 과정

    • flask cors 설정에 뭔가 문제가 있었는지 다시 찾아봄.

      • Access-Control-Allow-Origin default 설정이 ”*” => pass
    • nginx 설정이 뭔가 이상한가 다시 찾아봄.

      • Access-Control-Allow-Origin ”*” 인데

        • Access-Control-Allow-Origin 을 프론트 주소로 변경
      • Access-Control-Allow-Credential true 로 바꾸고 나서 동작이 됨.
    • flask cors 에서도 하는건데?

      • Access-Control-Allow-Credential 을 헤더에 넣을 경우,
      • Access-Control-Allow-Origin 에 ”*” 을 넣을 수 없음
    • Access-Control-Allow-Credential 헤더가 왜 필요한가?

      자바스크립트로 크로스 오리진 요청을 보내는 경우, 기본적으로 쿠키나 HTTP 인증 같은 자격 증명(credential)이 함께 전송되지 않습니다.

      HTTP 요청의 경우 대개 쿠키가 함께 전송되는데, 자바스크립트를 사용해 만든 크로스 오리진 요청은 예외이죠.

      따라서 fetch('http://another.com')를 사용해 요청을 보내도 another.com 관련 쿠키가 함께 전송되지 않습니다.

      왜 그럴까요?

      이런 예외가 생긴 이유는 자격 증명과 함께 전송되는 요청의 경우 영향력이 강하기 때문입니다. 크로스 오리진 요청 시 자격 증명을 함께 전송할 수 있으면 사용자 동의 없이 자바스크립트로 민감한 정보에 접근할 수 있게 됩니다.

      그럼에도 불구하고 서버에서 이를 허용하고 싶다면, 자격 증명이 담긴 헤더를 명시적으로 허용하겠다는 세팅을 서버에 해줘야 합니다.

      fetch 메서드에 자격 증명 정보를 함께 전송하려면 다음과 같이 credentials: "include" 옵션을 추가하면 됩니다.

      fetch('http://another.com', {
        credentials: "include"
      });

      이렇게 옵션을 추가하면 fetch로 요청을 보낼 때 another.com에 대응하는 쿠키가 함께 전송됩니다.

      자격 증명 정보가 담긴 요청을 서버에서 받아들이기로 동의했다면 서버는 응답에 Access-Control-Allow-Origin 헤더와 함께 Access-Control-Allow-Credentials: true 헤더를 추가해서 보냅니다.

      예시:

      200 OK
      Access-Control-Allow-Origin: https://javascript.info
      Access-Control-Allow-Credentials: true

      자격 증명이 함께 전송되는 요청을 보낼 땐 Access-Control-Allow-Origin*을 쓸 수 없습니다. 위 예시에서처럼 Access-Control-Allow-Origin엔 정확한 오리진 정보만 명시되어야 합니다. 이런 제약이 있어야 어떤 오리진에서 요청이 왔는지에 대한 정보를 서버가 신뢰할 수 있기 때문입니다.

      https://ko.javascript.info/fetch-crossorigin#ref-955

      • js fetch를 사용 한다면 credentials: “include”
      • XMLHttpRequest 객체를 사용한다면, withCredential = true 로 세팅해 놓았기 때문이다.

        • 쿠키기반 인증을 사용하게 된다면… token기반으로 변경이 필요해진다.

flask CORS 세팅 값 알아보기

  • CORSALLOWHEADERS: “*”

    • CORS 요청 가능한 헤더
  • CORSALWAYSSEND: True

    • ORIGIN 헤더 없어도 Response 보냄
  • CORSAUTOMATICOPTIONS: True

    • flask default option handling 덮어씀
  • CORSEXPOSEHEADERS: None

    • Access-Control-Expose-Headers 에 들어갈 것들 설정
  • CORSINTERCEPTEXCEPTIONS: True

    • flask 에러 핸들러 쓸지 말지
  • CORSMAXAGE: None

    • cors request cached duration
  • CORS_METHODS: [”GET”, “HEAD”, “POST”, “OPTIONS”, “PUT”, “PATCH”, “DELETE”]

    • cors 요청 가능한 http method
  • CORS_ORIGINS: “*”

    • cors 요청 가능한 주소, * 이면 모든 요청, 특정 url로 고정되면 해당 url만
  • CORS_RESOURCES: r”/*”

    • cors 적용되는 resource path 등록
  • CORSSENDWILDCARD: False

    • true 이고, CORSALLOWHEADERS가 * 이라면 *
    • false 이고, CORSALLOWHEADERS가 * 이라면 Requests의 Origin을 보냄
  • CORSSUPPORTSCREDENTIALS: False

  • CORSVARYHEADER: True

    • Vary response header is set to Origin

해결법

    1. 프론트에게 credential을 꺼달라고 한다.
    2. flask cors 에서

      1. CORSALLOWHEADERS = “프론트 주소”
      2. CORSSUPPORTSCREDENTIALS = True

배운것

  • 문제 진단을 제대로 해야한다.
  • 개념은 잘 알고 넘어가야 한다.