인증 & 인가 (Authentication & Authorization)
JWT (JSON Web Token)
세 부분이 .으로 구분된 Base64URL 인코딩 토큰.
Header.Payload.Signature
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
구성
// Header
{ "alg": "HS256", "typ": "JWT" }
// Payload (공개 정보 — 민감 정보 금지)
{
"sub": "1234567890", // Subject (사용자 ID)
"iat": 1516239022, // Issued At
"exp": 1516242622, // Expiration
"role": "admin"
}
// Signature
HMACSHA256(base64(header) + "." + base64(payload), secret)Access Token + Refresh Token 패턴
Access Token — 짧은 만료 (15분~1시간), API 요청에 사용
Refresh Token — 긴 만료 (7일~30일), DB에 저장, Access Token 재발급용
// Node.js (jsonwebtoken)
import jwt from 'jsonwebtoken'
const ACCESS_SECRET = process.env.JWT_ACCESS_SECRET!
const REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!
function issueTokens(userId: number) {
const accessToken = jwt.sign({ sub: userId }, ACCESS_SECRET, { expiresIn: '15m' })
const refreshToken = jwt.sign({ sub: userId }, REFRESH_SECRET, { expiresIn: '7d' })
return { accessToken, refreshToken }
}
function verifyAccess(token: string) {
return jwt.verify(token, ACCESS_SECRET) as { sub: number }
}JWT 취약점 & 주의사항
| 취약점 | 설명 | 대응 |
|---|---|---|
alg: none 공격 |
서명 검증 우회 | 알고리즘 명시적으로 지정 |
| 약한 시크릿 | 브루트포스 가능 | 256비트 이상 랜덤 시크릿 |
| Payload 민감 정보 | Base64 디코딩으로 열람 가능 | 민감 정보 포함 금지 |
| XSS로 토큰 탈취 | localStorage 저장 시 취약 | HttpOnly Cookie 사용 |
OAuth 2.0
제3자에게 권한을 위임하는 표준 프로토콜.
Authorization Code Flow (웹 서버)
User → Client → AuthServer: 인증 요청
AuthServer → User: 로그인 + 동의
AuthServer → Client: Authorization Code
Client → AuthServer: Code + Client Secret
AuthServer → Client: Access Token + Refresh Token
Client → ResourceServer: Access Token으로 API 호출
세션 vs JWT
| 항목 | 세션 | JWT |
|---|---|---|
| 상태 | Stateful (서버에 저장) | Stateless |
| 확장성 | 수평 확장 어려움 | 쉬움 |
| 로그아웃 | 즉시 무효화 가능 | 만료까지 유효 (블랙리스트 필요) |
| 저장 위치 | 서버 메모리/DB | 클라이언트 |