쿠키와 세션에 대해서 알아보기 전에 HTTP 프로토콜의 특성을 살펴보고자 한다.
HTTP는 인터넷 상에서 데이터를 주고 받기 위한 서버-클라이언트 모델을 따르는 프로토콜이다.
클라이언트가 서버에게 요청(request)을 보내면 서버는 응답(response)을 보냄으로써, 데이터를 교환한다.
HTTP는 비연결성 (connectionless)
, 무상태성 (stateless)
이라는 특징을 가지고 있다.
HTTP는 요청에 대한 응답을 처리 완료하게 되면, 연결을 끊어 버린다.
즉, 클라이언트에 대한 이전의 상태 정보 및 현재 통신의 상태가 남아있지 않게 되는 것이다.
비연결성 (connectionless) : 클라이언트가 서버에 요청했을 때, 해당 요청에 맞는 응답을 보낸 후 연결을 끊는 처리 방식.
무상태성 (stateless) : 클라이언트와 첫번째 통신에서 데이터를 주고받았다 해도 두 번째 통신에서는 이전 데이터를 유지하지 않는다.
쿠키는 다음의 세 가지 목적을 위해 사용된다.
세션 관리 (Session Management)
개인화 (Personalization)
트래킹 (Tracking)
쿠키의 데이터 형태는 key와 Value로 구성된 String이다. 4KB 이상 저장할 수 없다.
HTTP 요청을 수신할 때, 서버는 응답과 함께 Set-Cookie Header를 전송할 수 있다.
쿠키는 보통 브라우저에 의해 저장되며, 그 후 쿠키는 같은 서버에 의해 만들어진 요청(request)들의 Cookie HTTP Header 안에 포함되어 전송된다.
만료일 또는 지속시간이 명시될 수 있으며, 만료된 쿠키는 더이상 보내지지 않는다.
또한, 브라우저마다 저장되는 쿠키는 다르다. 크롬에 남긴 쿠키는 인터넷 익스플로어에서 사용할 수 없으며 브라우저가 다르면 서버는 다른 사용자로 인식한다.
쿠키의 라이프타임은 Session Cookie와 Permanenet 쿠키 두 가지 방법으로 정의될 수 있다.
Session Cookie
Permanent Cookie
Secure : HTTPS 프로토콜 상에서 암호화된 요청일 경우에만 전송
HttpOnly : XSS 공격을 방지한다. Javascript의 document.cookie 객체에 접근할 수 없도록 한다.
Domain, Path : 쿠키의 스코프를 정의한다.
클라이언트의 웹 브라우저에 쿠키를 저장해놓고 매 요청마다 헤더에 쿠키를 넣어 전달하는 방식으로 인증을 구현할 경우 쿠키가 유출되거나 조작될 수 있는 보안상 결함이 존재한다.
개인 소유가 아닌 공용 컴퓨터에서 사용할 경우, 누구나 그 사용자의 비밀번호를 확인할 수 있게 되며 HTTP로 개인 정보를 주고 받는 것은 매우 위험하다.
Session이란 비밀번호를 비롯한 인증 정보를 쿠키가 아닌 서버 측에서 저장하고 관리하는 방식이다.
서버는 클라이언트에 로그인 요청에 대한 응답을 작성할 때, 인증 정보는 서버에 저장하고 사용자의 식별자인 JSESSIONID(session_id)를 쿠키에 담아 전송한다.
이후 클라이언트는 요청을 보낼 때마다 JSESSIONID 쿠키를 함께 보내고 서버는 이 ID의 유효성을 판별하고 클라이언트를 식별한다.
웹 브라우저에 쿠키를 저장하여 HTTP로 전송하는 방식 대신, 서버에 사용자의 인증 정보를 저장하며 session_id를 쿠키에 담아 전송하는 Session 방식이 보안상 훨씬 안전한 방법이라 할 수 있다.
session_id는 브라우저 단위로 저장되고, 브라우저 종료 시 소멸된다.
로그인한 사용자에 대해서만 세션을 생성하는 것이 아니다. 따라서 로그아웃을 하면 새로운 사용자로 인식하여 새로운 세션이 생성된다.
사용자의 로그인 상태, 닉네임 등 사용자가 요청할 때마다 필요한 정보들을 세션에 담아두면 사용자 DB에 접근할 필요가 없어 효율적이다.
클라이언트가 서버에 처음으로 요청(request)를 보냄 (session_id가 존재하지 않음)
서버에는 session_id 쿠키 값이 없는 것을 확인하고 새로 발급하여 응답함
클라이언트는 전달받은 session_id 값을 매 요청마다 헤더 쿠키에 넣어 저장
서버는 session_id를 통해 사용자를 식별한다.
클라이언트가 로그인 요청 시, 서버는 session을 로그인 사용자 정보로 갱신하고 새로운 session_id를 발급하여 응답한다.
이후 클라이언트는 로그인 사용자의 session_id 쿠키를 요청과 함께 전달하고 서버에서도 로그인된 사용자로 식별이 가능하게된다.
클라이언트가 브라우저를 종료할 시, session_id 쿠키를 제거하고 서버에서도 세션을 제거한다.
쿠키를 포함한 요청이 외부에 노출되더라도 세션 ID 자체는 유의미한 개인정보를 담고 있지 않으므로 쿠키 방식보다 훨씬 안전하다.
그러나 세션 하이재킹을 통해 희생자의 계정을 도용할 수 있다는 점이 있다.
각 사용자마다 고유한 세션 ID가 발급되므로, 요청이 들어올 때마다 회원 정보를 DB에 접근하여 확인할 필요가 없다.
서버에서 세션 저장소를 사용하므로 요청이 많아지면 서버의 부하가 심해진다. 그래서 Session을 무분별하게 사용하는 것은 서버 관점으로는 좋지 못하다.
HTTPS를 이용해 통신하는 것이 좋으며, Cookie와 마찬가지로 Session의 secure 옵션을 true로 주면 HTTPS에서만 세션 정보를 주고 받을 수 있으며, HttpOnly 옵션을 true로 주는 경우 js를 통해서 세션 쿠키를 사용할 수 없도록 강제할 수 있다.