[웹 개발 기초] 쿠키, 세션, 토큰, JWT 개념 완벽 정리 (보안과 캐시까지!)
웹 개발을 공부하다 보면 가장 헷갈리는 개념 중 하나가 바로 인증(Authentication)과 관련된 기술들이다.
쿠키, 세션, 토큰, 그리고 JWT까지… 각각의 차이점과 핵심 개념을 명확하게 정리해 보겠다.
1. 쿠키(Cookie)와 캐시(Cache)의 역할 분담
많은 사람들이 쿠키와 캐시를 혼동하곤 한다.
하지만 두 기술은 목적과 저장하는 데이터의 종류가 완전히 다르다.
- 쿠키 (Cookie)
- 데이터 형태: 아주 작은 텍스트 데이터(문자열)입니다. 이미지나 파일은 포함될 수 없음.
- 역할: 세션 ID, 다크모드 설정, ‘오늘 하루 이 창 열지 않음’ 같은 사용자의 간단한 상태나 설정 값을 브라우저에 저장.
- 특징: 브라우저(웹) 환경에 내장된 메커니즘으로, 웹 요청(Request)을 보낼 때마다 서버로 자동으로 실려 전송.
- 캐시 (Cache)
- 데이터 형태: 이미지, CSS 파일, JavaScript 파일 등 무거운 리소스.
- 역할: 최초 방문 시 서버에서 다운로드한 무거운 자원들을 브라우저에 임시 저장.
- 특징: 다음 방문 때 서버에 다시 요청하지 않고 내 컴퓨터(브라우저 캐시)에서 바로 꺼내 쓰기 때문에, 서버의 부담을 줄이고 페이지 로딩 속도를 획기적으로 높여줌.
2. 세션(Session) 기반 인증의 특징과 한계
- 개념: 유저가 로그인하면 서버가 그 정보를 서버 측 세션 DB에 저장하고, 이에 매칭되는 랜덤한
세션 ID를 생성해 클라이언트에게 전달하는 방식. 보통 이 세션 ID를 ‘쿠키’ 주머니에 담아주고 받음. - 장점: 유저 관리를 서버가 직접 하기 때문에 안정적이고 제어가 쉬움. (e.g. 특정 유저 강제 로그아웃, 중복 로그인 제한 등)
- 단점 (서버 리소스 부담): 유저가 많아질수록 세션 DB에 쌓이는 데이터가 늘어남. 또한, 클라이언트가 요청할 때마다 서버는 세션 DB를 조회해야 하므로 DB 리소스 부담(리소스 Hit)이 큼.
- 유효기간: 서버 측 세션 DB와 클라이언트 쿠키 모두 유효기간이 있음. 만약 유효기간이 없다면 서버 DB에 쓸모없는 데이터가 평생 쌓여 성능 저하를 일으키기 때문에, 일정 시간(e.g. 마지막 요청 후 30분~1시간)이 지나면 자동으로 만료되도록 설계됨.
3. 토큰(Token)의 등장과 네이티브 앱
- 웹 환경: 브라우저가 알아서 쿠키를 관리하고 자동으로 서버에 실어 보내주는 편리한 내장 메커니즘이 있어 쿠키를 주로 사용.
- 네이티브 앱 환경 (iOS / Android): 네이티브 앱에는 브라우저처럼 쿠키를 자동으로 관리해 주는 메커니즘이 없음.
- 토큰의 역할: 쿠키를 사용할 수 없는 앱 환경 등에서 통신하기 위해 등장한 개념. 복잡한 문자열 형태의 토큰을 발급받아 앱 내부의 안전한 저장소에 직접 보관하고, 서버에 요청할 때마다 HTTP 헤더에 이 토큰을 직접 실어서 보냄. (웹에서도 필요에 따라 토큰을 자유롭게 사용할 수 있다.)
4. JWT(JSON Web Token)의 오해와 진실, 그리고 보안 취약점
JWT는 토큰 인증 방식의 일종으로, 서버가 세션 DB를 유지하지 않아도 된다는 강력한 장점이 있다.
하지만 아래와 같이 흔히 하는 치명적인 오해가 있다.
“JWT는 암호화(Encryption)되어 있지 않다!“
JWT는 단순히 Base64라는 방식으로 인코딩(변환)되어 있을 뿐이므로, 누구나 디코딩만 하면 내부에 들어있는 유저 정보를 그대로 읽을 수 있다.
JWT의 ‘확인 서명(Signature)’은 정보를 숨기기 위한 암호화가 아니라, 토큰이 중간에 위조되거나 조작되지 않았는지 검증하기 위한 무결성 확인용이다.
따라서 JWT 내부에는 비밀번호나 주민번호 같은 민감한 보안 정보를 절대 넣으면 안된다.
🚨 JWT 탈취 위험 (토큰 하이재킹 & 재전송 공격)
서버는 토큰을 보낸 ‘사람’이 누구인지 확인하는 것이 아니라, 들어온 토큰의 ‘확인 서명’이 진짜인지만 검증한다.
따라서 해커가 중간에서 누군가의 JWT를 통째로 가로채면, 해커가 본인 컴퓨터로 그 토큰을 보내도 서버는 정상적인 유저로 착각하여 로그인을 허용하게 된다.
🛡️ 실제 서비스에서의 방어 전략
이러한 치명적인 취약점을 보완하기 위해 실제 서비스에서는 다음과 같은 보안 기술을 함께 사용한다.
- HTTPS(보안 통신) 의무화: 데이터가 오가는 선로 자체를 암호화하여 중간에서 토큰을 가로채는 행위(스니핑)를 원천 차단.
- Access / Refresh Token 이원화: 권한을 가진 실제 JWT(Access Token)의 유효기간을 15분~30분 정도로 매우 짧게 설정한다. 토큰이 가로채지더라도 금방 쓸모없어지게 만들고, 대신 유효기간이 긴
Refresh Token을 안전한 곳에 따로 보관해 두었다가 새로운 토큰을 주기적으로 재발급받는 방식을 취한다.
쿠키 vs 세션 vs 토큰
| 구분 | 쿠키 (Cookie) | 세션 (Session) | JWT (Token) |
|---|---|---|---|
| 저장 위치 | 클라이언트 (브라우저) | 서버 (세션 DB) | 클라이언트 (LocalStorage, 앱 저장소 등) |
| 데이터 형태 | 작은 텍스트 문자열 | DB 레코드 (유저 정보 매핑) | 인코딩된 문자열 (유저 정보 + 서명 포함) |
| 서버 부담 | 없음 | 유저 증가 시 DB 리소스 부담 큼 | DB 조회가 없어 서버 부담이 적음 |
| 제어력 | 낮음 | 높음 (강제 로그아웃 등 가능) | 낮음 (만료 전까지 토큰 자체 제어 불가) |
웹개발에서 필수적으로 알아야하는 상식중의 상식이다.
요즘 개발 공부를 하면 할수록 재밌다. 최초로 이런 것을 생각한 천재들이 존경스럽다.
언젠가 나도 그들이 되고 싶다.
[참고]
– 노마드 코더 Nomad Coders 영상