인증과 권한 흐름: 세션 vs JWT
Authentication·Authorization 분리, 세션/쿠키/CSRF, JWT 선택 기준을 정리
Posted
By okorion
인증과 권한 흐름: 세션 vs JWT
결론 요약
- 인증(Authentication)은 “너가 누구인지 확인”이고, 권한(Authorization)은 “무엇을 할 수 있는지 제한”이다.
- 세션 기반 인증은 서버가 상태(state)를 가진다는 전제 위에서 안전하지만, CSRF에 취약하다.
- JWT는 무상태(stateless)로 확장에 유리하지만, 폐기·저장 위치를 잘못 선택하면 보안이 급격히 나빠진다.
- 인증 설계는 라이브러리 선택 문제가 아니라 위협 모델(threat model)과 요청 흐름 설계 문제다.
- “언제 JWT를 쓰면 망하는지”를 말할 수 있어야 올바른 선택이다.
인증을 ‘동작 흐름’으로 이해하기
세션 / 쿠키 / CSRF 그리고 JWT 전환점
1️⃣ 정의: 인증과 권한을 먼저 분리하라
| 구분 | 의미 | 질문 |
|---|---|---|
| Authentication | 신원 확인 | “너 누구야?” |
| Authorization | 권한 검증 | “이 행동 해도 돼?” |
이 둘을 섞으면 다음 문제가 생긴다.
- 로그인 여부만으로 관리자 행동 허용
- 토큰 검증은 했지만 권한 체크 누락
결론: 인증은 “입장권”, 권한은 “좌석 등급”이다. 처리 시점과 책임이 다르다.
2️⃣ 쿠키와 세션: 역할과 차이를 구조로 이해
쿠키(Cookie)
- 저장 위치: 브라우저
- 역할: 요청마다 자동 전송되는 작은 데이터
- 용도: 세션 식별자, 설정 값
세션(Session)
- 저장 위치: 서버(DB/메모리/Redis)
- 역할: 로그인 상태 유지
- 식별자: 세션 ID(쿠키에 저장)
비교 표
| 항목 | 쿠키 | 세션 |
|---|---|---|
| 저장 위치 | 클라이언트 | 서버 |
| 민감 정보 | ❌ 직접 저장 금지 | ✅ 저장 가능 |
| 만료 | 브라우저/시간 | 서버 정책 |
| 확장성 | 높음 | 서버 자원 필요 |
| CSRF | 취약 | 취약(쿠키 기반) |
핵심은 이것이다. 세션은 안전하지만, 쿠키를 통해 식별되기 때문에 CSRF 표적이 된다.
3️⃣ 로그인 흐름: 요청 시퀀스로 보기
세션 기반 로그인 흐름 (텍스트 다이어그램)
1
2
3
4
5
6
7
8
9
10
11
12
13
[Client]
└─ POST /login (id, password)
↓
[Server]
├─ 사용자 검증
├─ 세션 생성 (sessionId)
└─ Set-Cookie: sessionId
↓
[Client]
└─ 이후 모든 요청에 Cookie 자동 전송
↓
[Server]
└─ sessionId로 사용자 식별
특징
- 브라우저가 쿠키를 자동 전송
- 서버는 상태를 기억
4️⃣ CSRF: 왜 세션 기반에서 특히 문제인가
CSRF란 무엇인가
- 사용자가 로그인된 상태를 악용해
- 의도하지 않은 요청을 다른 사이트에서 전송하게 만드는 공격
왜 세션 기반이 취약한가
- 쿠키는 출처와 무관하게 자동 전송
- 공격자는 “요청을 보내게”만 하면 된다
해결 개념: CSRF Token
- 서버가 예측 불가능한 토큰을 발급
- 클라이언트는 요청 바디/헤더에 토큰 포함
- 서버는 토큰 일치 여부 검증
핵심: “이 요청이 정말 이 화면에서 만들어졌는가?”를 검증
5️⃣ JWT: 왜 등장했고, 언제 쓰면 망하는가
JWT(JSON Web Token)의 핵심 아이디어
- 인증 정보를 서버가 아니라 토큰 자체에 포함
- 서버는 토큰 검증만 수행 (무상태)
장점
- 서버 확장 용이
- API 서버/마이크로서비스에 적합
- 모바일/외부 클라이언트 친화적
단점 (여기서 대부분 실패)
| 문제 | 설명 |
|---|---|
| 폐기 불가 | 유출 시 만료 전까지 유효 |
| 저장 위치 | localStorage → XSS 위험 |
| 크기 | 요청마다 전송 → 비용 |
| 상태 관리 | 로그아웃/강제 차단 어려움 |
“JWT 쓰면 망하는 경우”
- 브라우저 기반 서비스인데 localStorage 저장
- 짧은 만료 전략 없이 장기 토큰 사용
- 권한 정보까지 토큰에 과다 포함
결론 JWT는 “편해서” 쓰는 게 아니라 “무상태가 필수인 구조”에서만 써야 한다.
6️⃣ toy 예시: 로그인 / 로그아웃
세션 기반 로그인
1
2
POST /login → 세션 생성 → 쿠키 저장
POST /logout → 세션 삭제 → 쿠키 무효화
JWT 기반 로그인
1
2
POST /login → JWT 발급
Client 저장 → Authorization 헤더 전송
차이는 “상태를 누가 기억하는가”다.
7️⃣ 실무 예시: 관리자만 상품 수정
잘못된 접근
1
로그인 여부만 확인 → 상품 수정 허용
올바른 흐름
- 인증: 사용자 식별
- 권한: role === ‘admin’ 검증
- 행위 실행
1
2
if (!user) return 401;
if (user.role !== 'admin') return 403;
- 401: 인증 실패
- 403: 권한 부족
상태 코드도 의미에 맞게 분리해야 한다.
8️⃣ 언제 세션, 언제 JWT인가 (실무 결론)
세션이 유리한 경우
- 서버 렌더링(SSR)
- 브라우저 중심 서비스
- 강제 로그아웃/권한 변경 잦음
JWT가 유리한 경우
- 모바일/외부 클라이언트
- API 서버
- 수평 확장 필수 구조
인증은 “트렌드”가 아니라 요구사항의 함수다.
보안 체크리스트 (쿠키 옵션 포함)
- 인증과 권한을 분리해서 처리한다
- 세션 ID만 쿠키에 저장한다
- 쿠키에
HttpOnly설정 - 쿠키에
Secure설정(HTTPS) SameSite정책을 의도적으로 선택했다- CSRF 토큰을 사용한다(세션 기반)
- JWT 만료 시간을 짧게 설정했다
- JWT 저장 위치를 명확히 결정했다
- 권한 체크를 모든 보호 라우트에 적용했다
- 401과 403을 의미에 맞게 사용한다
This post is licensed under CC BY 4.0 by the author.
