CORS

강현구·2022년 4월 13일
0
post-custom-banner

CORS

Cross-Origin Resource Sharing

교차 출처의 자원 공유 = 출처가 다른 자원에 대한 공유

Origin (출처)

ex) 다음과 같은 주소가 있다고 했을 때, 각각의 아래와 같이 구분된다.
https:// github.com /nine57/learn_algorithm/search ?q=code

  1. https://
    = Protocol
  2. github.com
    = Host
  3. (생략됨) :8080
    = Port
  4. /nine57/learn_algorithm/search
    = Path
  5. ?q=code
    = Query String
  6. (생략됨)#foo
    = Fragment

여기서 출처에 대한 판단 요소는 Protocol, Host, Port의 세가지로,
각각에 대한 의미를 비교하는 것이 아니라 String자체를 비교하게 된다.

  • http를 사용한 URL과 https를 사용한 URL은 다른 Origin이다.
    - 프로토콜이 다르다.
  • http://127.0.0.1http://localhost 는 다른 Origin이다.
    - 의미상으로는 둘다 로컬호스트를 바라보게 되지만 문자열로 비교했을 때는 서로 다르다.
  • https://velog.iohttps://velog.io/@nine57 은 같은 Origin이다.
    - 프로토콜과 host가 동일하다. Path는 Origin 구분에 영향을 주지 않는다.

SOP란?

Same-Origin Policy (동일 출처 정책)

Web이라는 공개된 환경의 특성상 익명의, 부정한 의도가 담긴 공격에 취약할 수 밖에 없다.
이런 위험성 때문에 같은 출처일 경우에만 리소스를 받을 수 있도록 설정해둔 것이 SOP이다.
브라우져에서 http 통신을 할때는 SOP 정책하에 하게된다.
즉, 원칙적으로는 출처가 다른 외부의 리소스들을 사용할 수 없다는 얘기인데, 그렇게 되면 Web의 장점을 사용하기 힘들어진다.
따라서 제한적인 상황에서 SOP를 통과할 수 있게 하는 예외 조건이 있다.

  • CORS 정책을 지킨 요청
  • 실행 가능한 스크립트
  • 랜더될 이미지
  • 스타일 시트
  • ...

CORS & SOP가 나온 이유

  • CSRF (위키피디아)
    (Cross Site Request Forgery) 웹 어플리케이션 취약점 중 하나로, 인터넷 사용자가 의지와 무관하게 공격자가 의도한 행위(수정, 삭제 등등)를 특정 웹사이트에 요청하게 만드는 공격
  • XSS (위키피디아)
    (Cross Site Scripting) 공격자가 사용자의 브라우저에 스크립트가 실행되도록 하여 사용자의 세션을 가로채거나, 웹사이트를 변조하거나, 악의적 콘텐츠를 삽입하거나, 또는 피싱 공격 등을 진행하는 것을 말한다.
    XSS 공격은 스크립트 언어와 취약한 코드를 대상으로하게된다.

CORS 예시

Origin(@request) == Access-Control-Allow-Origin(@response)
위의 두개의 헤더가 같다면 같은 출처라고 인식한다.

Preflight Request

OPTIONS라는 메소드를 사용해서 예비 요청을 먼저 보내, 서버에게 요청을 보낼 수 있는지를 확인하고 요청에 대한 허가가 떨어지면 본 요청을 보내게 된다.

  • Origin에 대한 정보 뿐만 아니라 예비요청 이후 어떤 본요청을 보낼 지에 대한 정보도 포함된다. (Access-Control-Request-Headers, Access-Control-Request-Method 등)
  • 요청의 Origin 과 응답의 Access-Control-Allow-Origin을 브라우저가 비교, 출처가 다르다면 에러발생, 아니라면 본 요청을 보낸다.

PUT이나, DELETE같은 요청을 보낼 경우 서버 쪽에 변경이 발생하게 되는데, SOP는 브라우져 사이드에서 확인을 하는 정책이다. (서버나 클라이언트 사이드의 정책이 아니다!)
만약, SOP에 위배되는 상황인데 위와 같은 요청을 보낸다면, 변경하면 안되는 상황임에도 서버는 그에 대한 구별없이 요청을 수행하고 완료되었다고 200OK를 보낸다.
이에 대한 안전 절차로서 예비 요청을 보내서 요청을 보내도 되는지에 대한 확인을 하는절차이다.

Simple Request

예비 요청없이 바로 본요청을 보낸다.
본 요청에서 SOP여부를 같이 판단하고 요청을 처리하게 되고, 따라서 사용하는데 조금 더 제약이 있다.

  • 요청의 메소드는 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만 허용된다.

위의 제약 사항을 볼 때, REST API에서 jwt 담아서 보내는 요청은 수행할 수 없을 을 알 수 있다.(Token을 담는 Authorization 헤더가 없을 뿐만 아니라, Content-type에 Json이 없다.)
REST 기반의 API에서는 잘 사용하지 않는 방법.

Credentialed Request

쿠키에 인증 정보를 담아 서버 쪽에서 인증 정보를 검증하고 응답하게 하는 방법.
인증 정보 유무에 따라 다음과 같이 옵션을 지정해서 요청을 보낸다.
보안상 더 안전한 방식을 취하고자 함

옵션 값설명
same-origin(기본값)같은 출처 같 요청에만 인증 정보를 담는다.
Include모든 요청에 인증정보를 담는다.
Omit모든 요청에 인증정보를 담지 않는다.

이 방법에도 일부 제약사항이 있다.

  • Access-Control-Allow-Origin에는 *(와일드카드)를 사용할 수 없고, 명시적인 URL 이어야 한다.
  • 응답 헤더에는 반드시 Access-Control-Allow-Credentials: true가 존재해야한다.

그래서

Server side 에서는
응답헤더에 올바른 Access-Control-Allow-Origin이 내려올 수 있도록 세팅이 필요하다.

Client side 에서는
Webpack Dev Server로 리버스 프록싱하여 우회가 가능
But, 로컬 환경에서만 가능하므로 결론적으로는 서버사이드에서 해결하는 것이 맞다.

Django 에서 사용하는 django-cors-headers 라이브러리가 이를 해결해주는 것!

Reference : [10분 테코톡] 🤠럿고의 CORS

profile
한걸음씩
post-custom-banner

0개의 댓글