1. 세션 기반 인증 vs 토큰 기반 인증
세션 기반 인증 (Session-based Authentication)
로그인 시 서버가 세션을 생성하고, 클라이언트는 세션 ID만 쿠키로 보관하는 방식입니다.
1. 클라이언트 → 로그인 요청
2. 서버 → 세션 생성 (서버 메모리/DB에 저장)
3. 서버 → 세션 ID를 쿠키로 응답
4. 클라이언트 → 이후 요청마다 쿠키(세션 ID) 포함
5. 서버 → 세션 ID로 서버에 저장된 세션 조회 → 인증 확인
장점
- 서버에서 세션을 직접 관리하므로 즉시 무효화(로그아웃) 가능
- 클라이언트에 민감한 정보가 남지 않음
단점
- 서버가 여러 대면 세션 공유 문제 발생 (Redis 같은 세션 스토리지 필요)
- 서버 메모리 사용량 증가
- 모바일 앱, 타 도메인 API 호출에 쿠키 사용이 불편
보안 고려사항
- HTTPS 필수 (쿠키 탈취 방지)
- HttpOnly, Secure 쿠키 속성 설정
- 세션 고정 공격 방지: 로그인 성공 시 세션 ID 재발급
- 세션 만료 시간 설정
토큰 기반 인증 (Token-based Authentication / JWT)
로그인 시 서버가 토큰을 발급하고, 클라이언트가 토큰을 직접 보관하는 방식입니다.
1. 클라이언트 → 로그인 요청
2. 서버 → JWT 토큰 생성 후 응답 (서버에 저장 X)
3. 클라이언트 → 토큰을 로컬스토리지 또는 메모리에 저장
4. 클라이언트 → 이후 요청마다 Authorization: Bearer {token} 헤더에 포함
5. 서버 → 토큰 서명 검증만으로 인증 확인 (DB 조회 X)
장점
- 서버가 상태를 저장하지 않음 (Stateless) → 수평 확장 용이
- 모바일, 타 도메인 API 호출에 적합
- 마이크로서비스 환경에서 서비스 간 인증 전달 편리
단점
- 토큰 발급 후 즉시 무효화 불가 (만료 전까지 유효)
- 토큰 크기가 세션 ID보다 큼
- 탈취 시 만료 전까지 악용 가능
보안 고려사항
- Access Token 만료 시간 짧게 설정 (15분~1시간)
- Refresh Token으로 재발급 구조 구성
- 토큰은 HttpOnly 쿠키에 저장 (XSS 방지)
- 로컬스토리지 저장은 XSS에 취약하므로 지양
- 알고리즘은 HS256 이상 사용
비교 정리
항목 세션 기반 토큰 기반
| 상태 저장 위치 | 서버 | 클라이언트 |
| 확장성 | 낮음 (세션 공유 필요) | 높음 (Stateless) |
| 즉시 무효화 | 가능 | 어려움 |
| 모바일/API 적합성 | 낮음 | 높음 |
| 주요 보안 위협 | 세션 탈취, 고정 공격 | 토큰 탈취, XSS |
2. OAuth 2.0
OAuth 2.0이란?
사용자가 비밀번호를 직접 제공하지 않고, 제3자 애플리케이션에 제한적인 접근 권한을 위임하는 표준 프로토콜입니다.
예: "구글 계정으로 로그인" 버튼을 누를 때 OAuth 2.0이 동작합니다.
주요 컴포넌트
컴포넌트 역할 예시
| Resource Owner | 실제 사용자 | 나 (사용자) |
| Client | 권한을 요청하는 앱 | 우리가 만든 서비스 |
| Authorization Server | 인증 및 토큰 발급 | Google, Kakao |
| Resource Server | 보호된 자원을 가진 서버 | Google API 서버 |
Authorization Code Grant 흐름
가장 안전하고 많이 쓰이는 방식입니다.
[1] 사용자 → 우리 서비스: "구글로 로그인" 클릭
[2] 우리 서비스 → Authorization Server:
GET /oauth/authorize
?response_type=code
&client_id=abc123
&redirect_uri=https://ourapp.com/callback
&scope=email profile
[3] Authorization Server → 사용자: "우리 앱이 이메일/프로필 접근을 요청합니다. 허용?"
[4] 사용자 → Authorization Server: 허용 클릭
[5] Authorization Server → 우리 서비스:
GET https://ourapp.com/callback?code=AUTHORIZATION_CODE
[6] 우리 서비스 → Authorization Server:
POST /oauth/token
{ code: AUTHORIZATION_CODE, client_secret: xxx }
[7] Authorization Server → 우리 서비스:
{ access_token: "...", refresh_token: "..." }
[8] 우리 서비스 → Resource Server:
GET /userinfo
Authorization: Bearer access_token
[9] Resource Server → 우리 서비스: 사용자 정보 반환
왜 Code를 먼저 받고 Token을 따로 요청하나?
[5] → [6] 단계를 보면 Access Token을 바로 주지 않고 Authorization Code를 먼저 줍니다.
이유는 보안 때문입니다.
- Authorization Code는 브라우저 URL에 노출됨 (짧은 유효시간, 1회용)
- Access Token은 서버 간 통신(백채널)으로만 교환 → URL에 절대 노출되지 않음
- client_secret을 포함해야 토큰 발급 가능 → 클라이언트 검증
PKCE (Proof Key for Code Exchange)
모바일 앱이나 SPA처럼 client_secret을 안전하게 보관할 수 없는 환경에서 사용합니다.
1. 클라이언트가 code_verifier (랜덤 문자열) 생성
2. code_verifier를 해시한 code_challenge를 인증 요청에 포함
3. 토큰 요청 시 원본 code_verifier 전송
4. 서버가 해시해서 비교 → 중간자 공격 방지
'Weekly Paper' 카테고리의 다른 글
| Weekly Paper #15 (0) | 2026.06.09 |
|---|---|
| Weekly Paper #14 (0) | 2026.06.09 |
| Weekly Paper #12 (0) | 2026.05.11 |
| Weekly Paper #10 (0) | 2026.04.01 |
| Weekly Paper #9 (0) | 2026.03.23 |