[Dreamhack] Web Hacking - Cookie & Session
쿠키(Cookie)
클라이언트의 IP 주소와 User-Agent는 매번 변경될 수 있는 고유하지 않은 정보일 뿐만 아니라, HTTP 프로토콜의 Connectionless와 Stateless 특징 때문에 웹 서버는 클라이언트를 기억할 수 없습니다.
Connectionless, Stateless 특성을 갖는 HTTP에서 상태를 유지하기 위해 쿠키(Cookie)가 탄생했습니다. 쿠키는 Key와 Value로 이뤄진 일종의 단위로, 서버가 클라이언트에게 쿠키를 발급하면, 클라이언트는 서버에 요청을 보낼 때마다 쿠키를 같이 전송합니다. 서버는 클라이언트의 요청에 포함된 쿠키를 확인해 클라이언트를 구분할 수 있습니다.
HTTP 프로토콜의 특징 | |
Connectionless | · 하나의 요청에 하나의 응답을 한 후 연결을 종료하는 것 · 특정 요청에 대한 연결은 이후의 요청과 이어지지 않고 새 요청이 있을 때마다 항상 새로운 연결을 맺음 |
Statless | · 통신이 끝난 후 상태 정보를 저장하지 않는 것 · 이전 연결에서 사용한 데이터를 다른 연결에서 요구할 수 없음 |
쿠키의 용도
쿠키는 클라이언트의 정보 기록과 상태 정보를 표현하는 용도로 사용합니다.
< 정보 기록 >
웹 서비스 사용 시 종종 등장하는 팝업 창에 "다시 보지 않기", "7일 간 표시하지 않기" 버튼이 있는 것을 확인할 수 있습니다. 웹 서버는 각 클라이언트의 팝업 옵션을 기억하기 위해 쿠키에 해당 정보를 기록하고, 쿠키를 통해 팝업 창 표시 여부를 판단합니다. 과거에는 클라이언트의 정보를 저장하기 위해 쿠키가 종종 사용됐습니다. 쿠키는 서버와 통신할 때마다 전송되기 때문에 쿠키가 필요 없는 요청을 보낼 때 리소스 낭비가 발생할 수 있습니다. 최근에는 이러한 단점을 보완하기 위해 Modern Storage APIs를 통해 데이터를 저장하는 방식을 권장하고 있습니다.
< 상태 정보 >
많은 웹 사이트에서는 회원가입과 로그인을 통해 개개인에게 맞춤형 서비스를 제공합니다. 웹 서버에서는 수 많은 클라이언트의 로그인 상태와 이용자를 구별해야 하는데, 이 때 클라이언트를 식별할 수 있는 값을 쿠키에 저장해 사용합니다.
쿠키가 없는 통신 VS 쿠키가 있는 통신
< 쿠키가 없는 통신 >
서버는 요청을 보낸 클라이언트가 누군지 알 수 없기 때문에 현재 어떤 클라이언트와 통신하는지 알 수 없습니다.
< 쿠키가 있는 통신 >
클라이언트는 서버에 요청을 보낼 때마다 쿠키를 포함하고, 서버는 해당 쿠키를 통해 클라이언트를 식별합니다.
>> 쿠키가 있어야 클라이언트가 데이터를 요구했을 때 서버가 쿠키 값을 식별하여 해당 데이터를 클라이언트에게 전달할 수 있다. 쿠키 값이 없으면 클라이언트가 서버에 요청을 보낼 때마다 일일히 데이터를 보내야 하는 번거로움이 생긴다.
>> 다른 예로 들자면 이전에 방문했던 사이트를 재방문하고 싶은 클라이언트와 방문 기록을 저장하는 서버와의 관계에서도 쿠키 값이 오고 갈 수 있다.
쿠키의 변조
중국집 식당에서 탕수육 이벤트를 진행하기 위해 쿠폰을 발행하여 방문할 때마다 도장을 찍어주는 방식으로 진행하고 있습니다. 도장은 식당에서 찍어주지만 쿠폰은 손님이 보관하기 때문에 손님은 쿠폰을 마음대로 할 수 있습니다. 만약 나쁜 마음을 품은 손님이 식당에서 사용하는 도장과 비슷한 도장을 구해 직접 쿠폰에 가짜 도장을 찍게 된다면 식당에서 이를 구분할 방법이 없습니다.
쿠키는 클라이언트의 브라우저에 저장되고 요청에 포함되는 정보이다. 따라서, 아래의 그림처럼 악의적인 클라이언트는 쿠키 정보를 변조해 서버에 요청을 보낼 수 있다. 만약 서버가 별다른 검증 없이 쿠키를 통해 이용자의 인증 정보를 식별한다면 공격자가 타 이용자를 사칭해 정보를 탈취할 수 있다.
세션(Session)
쿠키에서 인증 상태를 저장하지만 클라이언트가 인증 정보를 변조할 수 없도록 세션(Session)을 사용한다. 세션은 인증 정보를 서버에 저장하고 해당 데이터에 접근할 수 있는 키(유추할 수 없는 랜덤한 문자열)를 만들어 클라이언트에 전달하는 방식으로 작동한다. 해당 키를 일반적으로 Session ID라고 하는데, 브라우저는 해당 키를 쿠키에 저장하고 이후에 HTTP 요청을 보낼 때 사용한다. 서버는 요청에 포함된 키에 해당하는 데이터를 가져와 인증 상태를 확인한다.
쿠키의 변조에서 봤던 예시를 다시 생각해보자.
중국집 식당의 탕수육 이벤트 쿠폰 도장을 조작하는 손님이 생겼습니다. 손님이 갖고 있는 쿠폰은 손님이 조작할 수 있기 때문에 쿠폰에 도장을 찍지 않고 손님마다 랜덤한 문자열을 적은 쿠폰을 주었습니다. 손님이 쿠폰을 식당에 제시하면 식당에 보관 중인 메모장에서 쿠폰에 적힌 문자열과 방문 횟수를 기록하는 방식으로 이벤트를 운영했습니다. 이 때문에 손님은 쿠폰에 적힌 랜덤한 문자열은 조작할 수 있지만 매장에 기록된 방문 횟수는 조작할 수 없게 되었습니다.
쿠키는 데이터 자체를 이용자가 저장하며, 세션은 서버가 저장한다는 핵심적인 차이가 있다.
쿠키 적용법
쿠키는 클라이언트에 저장되기 때문에 클라이언트는 저장된 쿠키를 조회, 수정, 추가할 수 있다. 클라이언트가 서버에 요청을 보낼 때 저장된 쿠키를 요청 헤더에 넣어 전송하기 때문에 이용자가 요청을 보낼 때 쿠키 헤더를 변조할 수 있다. 쿠키를 설정할 때에는 만료 시간을 지정할 수 있고, 만료 시간 이후에는 클라이언트에서 쿠키가 삭제된다. 쿠키의 만료는 클라이언트(브라우저)에서 관리된다.
쿠키는 서버와 클라이언트 둘 다 설정할 수 있으며, 설정하는 방법은 아래와 같다.
< 서버 >
HTTP 응답 중 헤더에 쿠키 설정 헤더(Set-Cookie)를 추가하면 클라이언트의 브라우저가 쿠키를 설정한다.
HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
Set-Cookie: name=test;
Set-Cookie: age=22; Exprires=Sun, 30 Jul 2023 03:09:40 GMT;
...
< 클라이언트 >
JavaScript를 사용하여 쿠키를 설정한다.
document.cookie = "name=test;"
document.cookie = "age=22; Exprires=Sun, 30 Jul 2023 03:09:40 GMT;"
< Chrome Console을 활용하여 쿠키 정보 확인하는 방법 >
※ 쿠키 옵션(HttpOnly)에 따라 JavaScript에서 쿠키 확인이 불가능할 수 있음
< Chrome Application을 활용하여 쿠키 정보 확인하는 방법 >
Keyword |
|
Connectionless | 하나의 요청에 하나의 응답을 한 후 연결을 종료하는 것 |
Stateless | 통신이 끝난 후 상태 정보를 저장하지 않는 것 |
쿠키(Cookie) | HTTP에서 상태를 유지하기 위해 사용하는 Key-Value 형태의 값 |
세션(Session) | 쿠키에 포함된 Sesion ID를 사용해 서버에 저장된 세션 데이터를 접근하는 방식 |
세션 하이재킹(Session Hijacking) | 타 이용자의 쿠키를 훔쳐 인증 정보를 획득하는 공격 |