🔐 토큰 저장 방식 완벽 가이드
위험
localStorage
✅ 장점
- 구현이 매우 간단
- 페이지 새로고침해도 유지
- 탭을 닫아도 데이터 보존
- 용량이 큼 (약 5-10MB)
❌ 단점
- XSS 공격에 매우 취약
- JavaScript로 접근 가능
- 악성 스크립트가 토큰 탈취 가능
- 브라우저 개발자도구에서 확인 가능
// 저장 localStorage.setItem('accessToken', token); // 사용 const token = localStorage.getItem('accessToken'); headers: { 'Authorization': `Bearer ${token}` } // ⚠️ XSS 공격으로 쉽게 탈취당함! console.log(localStorage.getItem('accessToken'));
보통
sessionStorage
✅ 장점
- 탭을 닫으면 자동 삭제
- 다른 탭과 격리됨
- localStorage보다 상대적으로 안전
- 구현이 간단
❌ 단점
- 여전히 XSS 공격에 취약
- 페이지 새로고침 시 로그인 풀림
- JavaScript로 접근 가능
- 사용자 경험이 떨어짐
// 저장 sessionStorage.setItem('accessToken', token); // 사용 const token = sessionStorage.getItem('accessToken'); // 탭 닫으면 자동 삭제되지만 XSS 여전히 위험!
보통
메모리 (JavaScript 변수)
✅ 장점
- Storage보다 안전
- 페이지 새로고침 시 자동 삭제
- 개발자도구에서 쉽게 확인 불가
- XSS 공격 난이도 상승
❌ 단점
- 페이지 새로고침 시 로그인 풀림
- 여전히 XSS 공격 가능
- 상태 관리가 복잡
- 사용자 경험 저하
// React 예시 const [accessToken, setAccessToken] = useState(null); // Zustand 예시 const useAuthStore = create((set) => ({ accessToken: null, setToken: (token) => set({ accessToken: token }) })); // 새로고침하면 다시 로그인해야 함
안전
HttpOnly Cookie
✅ 장점
- XSS 공격으로부터 안전
- JavaScript로 접근 불가
- 브라우저가 자동 관리
- CSRF 토큰과 함께 사용 시 매우 안전
❌ 단점
- CSRF 공격에 취약할 수 있음
- 서버 설정이 복잡
- 모바일 앱에서 사용 어려움
- 디버깅이 어려움
// 서버에서 설정 Cookie cookie = new Cookie("accessToken", token); cookie.setHttpOnly(true); // JavaScript 접근 차단 cookie.setSecure(true); // HTTPS만 허용 cookie.setSameSite("Strict"); // CSRF 방지 response.addCookie(cookie); // 브라우저가 자동으로 전송 (프론트엔드 작업 불필요)
최고
Secure + SameSite Cookie
✅ 장점
- XSS와 CSRF 모두 방어
- HTTPS에서만 전송
- 크로스사이트 요청 차단
- 최고 수준의 보안
❌ 단점
- HTTPS 필수
- 설정이 가장 복잡
- 브라우저 호환성 고려 필요
- 개발 환경 설정 까다로움
// 최고 보안 설정 Cookie cookie = new Cookie("accessToken", token); cookie.setHttpOnly(true); // XSS 방지 cookie.setSecure(true); // HTTPS만 cookie.setSameSite("Strict"); // CSRF 방지 cookie.setPath("/"); cookie.setMaxAge(15 * 60); // 15분 response.addCookie(cookie);
📊 보안성 비교표
| 저장 방식 | XSS 보안 | CSRF 보안 | 구현 난이도 | 사용자 경험 | 총점 |
|---|---|---|---|---|---|
| localStorage | 위험 | 안전 | 쉬움 | 좋음 | ❌ |
| sessionStorage | 위험 | 안전 | 쉬움 | 보통 | ❌ |
| 메모리 | 보통 | 안전 | 보통 | 나쁨 | ⚠️ |
| HttpOnly Cookie | 안전 | 보통 | 보통 | 좋음 | ✅ |
| Secure + SameSite | 안전 | 안전 | 어려움 | 좋음 | 🏆 |
🏆 베스트 프랙티스 추천
현대적인 웹 애플리케이션을 위한 최적의 토큰 저장 전략
🎯 프로덕션 환경
HttpOnly + Secure + SameSite Cookie
- Access Token: 짧은 수명 (15분)
- Refresh Token: 긴 수명 (7일)
- HTTPS 필수
- CSRF 토큰 추가
🛠️ 개발 환경
HttpOnly Cookie (간소화)
- Secure 옵션 비활성화
- SameSite 설정 완화
- 디버깅을 위한 로깅 추가
- 점진적 보안 강화
🔧 구현 가이드
1
서버 측 Cookie 설정
JWT 토큰을 HttpOnly Cookie로 설정하고 보안 옵션을 활성화합니다.
2
CSRF 보호 구현
Double Submit Cookie 패턴이나 CSRF 토큰을 사용하여 CSRF 공격을 방어합니다.
3
자동 토큰 갱신
Refresh Token으로 Access Token을 자동 갱신하는 로직을 구현합니다.
4
에러 처리
토큰 만료, 인증 실패 등의 상황에 대한 적절한 에러 처리를 구현합니다.
⚠️ 중요한 보안 고려사항
- 절대 localStorage에 중요한 토큰 저장 금지 - XSS 공격에 매우 취약
- HTTPS 필수 - Secure Cookie는 HTTPS에서만 동작
- 토큰 수명 최소화 - Access Token은 15-30분, Refresh Token은 1-7일
- 로그아웃 시 토큰 무효화 - 서버에서 토큰을 블랙리스트에 추가