🚀 Refresh Token 저장 방식 & 만료된 토큰 관리 방법
✅ Refresh Token 저장 방식 (DB vs 클라이언트 vs Redis)
✅ Refresh Token 보안 위험 (XSS/CSRF 공격 대응 방법)
✅ 만료된 Refresh Token 관리 & 강제 로그아웃 기능 구현 방법
1️⃣ Refresh Token 저장 방식
Refresh Token은 어디에 저장하느냐에 따라 보안성과 사용자 경험이 달라짐.
보편적으로 아래 3가지 방식을 고려할 수 있음.
🔹 1. 클라이언트(LocalStorage, Cookie) 저장 방식 (❌ 보안 취약)
✅ 장점:
- 서버 부담이 없음 (Stateless)
- 클라이언트가 저장하고 필요할 때 사용
❌ 단점:
- LocalStorage에 저장 시 XSS 공격에 취약 (해커가 자바스크립트로 접근 가능)
- 쿠키에 저장 시 CSRF 공격 위험 (쿠키 탈취 가능)
- Refresh Token이 탈취되면 무제한 Access Token 발급 가능 → 매우 위험
📌 결론:
보안이 중요한 경우, 클라이언트에 Refresh Token을 직접 저장하는 방식은 피하는 것이 좋음 ❌
🔹 2. DB(MySQL, PostgreSQL 등) 저장 방식 (✅ 안전한 방식)
✅ 장점:
- Refresh Token을 DB에 저장하고 관리 가능
- 토큰을 탈취당했을 경우 강제 로그아웃(토큰 폐기) 가능
❌ 단점:
- DB 조회 부담이 증가 (로그인 시, 토큰 갱신 시마다 DB 접근)
- 분산 서버 환경에서는 DB 동기화 문제 발생 가능
📌 구현 방식:
CREATE TABLE refresh_tokens (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
token VARCHAR(512) NOT NULL,
expires_at TIMESTAMP NOT NULL
);
📌 유효하지 않은 Refresh Token을 DB에서 삭제하면 즉시 무효화 가능!
🔹 3. Redis 캐시 저장 방식 (✅ 보안 & 성능 균형)
✅ 장점:
- 빠른 속도로 토큰을 저장하고 조회 가능 (DB보다 성능 좋음)
- 만료 시간이 지나면 자동 삭제 가능 (TTL 설정)
- 강제 로그아웃 시 즉시 삭제 가능
❌ 단점:
- Redis가 다운되면 로그인 유지 불가
- 추가적인 Redis 인프라 운영 비용 발생
📌 구현 방식 (Spring Boot + Redis 적용 예시)
@RedisHash("refreshToken")
public class RefreshToken {
@Id
private String token;
private Long userId;
private LocalDateTime expiresAt;
}
📌 Refresh Token을 Redis에 저장하면 빠르게 조회 가능 & 일정 시간이 지나면 자동 만료됨!
2️⃣ Refresh Token 보안 위험 & 대응 방법
🔹 Refresh Token이 클라이언트에 저장될 경우 발생하는 보안 문제
- XSS 공격 (Cross-Site Scripting)
- 해커가 자바스크립트를 삽입하여 LocalStorage에서 토큰을 탈취할 수 있음
- 해결책: LocalStorage 대신 HttpOnly Cookie 사용 or 서버 저장 방식 사용
- CSRF 공격 (Cross-Site Request Forgery)
- 사용자의 인증 정보를 탈취하여 공격자가 다른 사용자로 위장할 수 있음
- 해결책: SameSite 설정을 통해 다른 사이트에서의 요청을 차단
📌 쿠키 저장 시 보안 설정 예시:
ResponseCookie cookie = ResponseCookie.from("refreshToken", refreshToken)
.httpOnly(true) // XSS 공격 방지
.secure(true) // HTTPS 환경에서만 전송
.sameSite("Strict") // CSRF 방지
.maxAge(Duration.ofDays(7)) // 7일간 유효
.path("/")
.build();
✅ HttpOnly + Secure + SameSite 속성을 설정하면 보안 강화 가능!
3️⃣ 만료된 Refresh Token 관리 & 강제 로그아웃 구현
🔹 Refresh Token이 탈취되었을 경우 문제점
- Refresh Token이 해커에게 탈취되면 Access Token을 무제한으로 갱신 가능
- 로그아웃을 하더라도, Refresh Token이 살아 있으면 계속 사용할 수 있음
🔹 Refresh Token 강제 만료(로그아웃) 구현 방법
✅ DB 저장 방식일 경우
- 사용자가 로그아웃하면 DB에서 Refresh Token을 삭제하여 즉시 무효화
DELETE FROM refresh_tokens WHERE user_id = ?;
- Refresh Token을 해커가 탈취했더라도 삭제된 토큰은 사용할 수 없음
✅ Redis 저장 방식일 경우
- Redis에서 해당 사용자의 Refresh Token 삭제
redisTemplate.delete("refreshToken:" + userId);
📌 이렇게 하면 해당 사용자는 Refresh Token이 만료되므로 재로그인 필요!
🎯 결론: 안전한 Refresh Token 저장 및 관리 방법
🔹 추천하는 저장 방식
✅ DB 저장 (보안이 중요할 경우 추천)
✅ Redis 저장 (보안 & 성능 균형을 원할 경우 추천)
❌ LocalStorage 저장 (보안 취약하므로 추천하지 않음)
🔹 Refresh Token 보안 강화 방법
- HttpOnly, Secure, SameSite 설정으로 CSRF/XSS 공격 방어
- 만료된 Refresh Token을 즉시 폐기할 수 있도록 관리(DB, Redis 활용)
- 로그아웃 시 Refresh Token을 삭제하여 강제 만료 처리
🔹 Refresh Token을 안전하게 관리하면?
✅ 보안 강화 + 사용자 경험 향상 (자동 로그인 유지 가능)
✅ Access Token을 짧게 설정하여 보안성을 유지하면서도 편리한 로그인 가능
🔥 이제 보안 강화를 위해 Refresh Token을 안전하게 저장하고, 강제 로그아웃 기능도 추가해보자! 🚀