
JWT 토큰의 장점은 무상태 방식으로 동작하기 때문에 이전 요청의 상태나 다른 데이터를 참조하지 않고 독립적으로 처리한다는 점이다. JWT를 이용하면 로그인 시 세션 불일치 문제를 걱정하거나 별도의 외부 저장소를 만들 필요가 없어진다.
하지만, JWT는 토큰 탈취에 취약하다.
공격자는 토큰이 만료될 때까지 정상 사용자처럼 서비스에 요청을 보낼 것인데,
사용자가 로그아웃하거나 관리자가 계정을 비활성화해도, 이미 발급된 Access Token이 만료되기 전까지는 계속 사용할 수 있다.
이를 해결하기 위해 클라이언트는 여러 방법을 모색할 수 있는데, 바로
Access Token은 서버측에서 관리할 수 있다.
그치만 오늘의 주제는 프론트엔드 관점이므로, 자세히 살펴보지 않는다.
가장 단순한 방법. Access Token을 그냥 자바스크립트 변수(또는 React state/context)에 담아두는 것이다.
const [accessToken, setAccessToken] = useState(null);
장점
단점
httpOnly 쿠키에 저장된 Refresh Token을 이용해 새로고침 시마다 토큰을 재발급받는 로직이 반드시 수반되어야 한다.서버가 Set-Cookie 헤더를 통해 브라우저 쿠키에 토큰을 저장하도록 지시하는 방식이다.
장점
HttpOnly 설정 시 XSS 방어: JavaScript(document.cookie)를 통한 접근이 차단되어 악성 스크립트로 토큰을 탈취할 수 없다.단점
| 속성 | 방어 대상 및 역할 |
|---|---|
HttpOnly | XSS 방어: JavaScript 접근 차단 |
Secure | 중간자 공격(MITM) 방어: HTTPS 암호화 통신 채널에서만 전송 허용 |
SameSite=Strict / Lax | CSRF 방어: 타 사이트에서의 교차 요청 제어 (Strict: 전면 차단, Lax: GET 등 안전한 탐색 시 일부 허용) |
웹 스토리지 API 중 하나로, 브라우저의 탭(세션) 단위로 독립된 저장 공간을 제공한다.
장점
단점
localStorage와 동일하게 JavaScript로 자유롭게 접근 가능하여 XSS 공격에 완전히 노출된다. (sessionStorage.getItem()으로 쉽게 추출 가능)브라우저를 닫거나 컴퓨터를 재부팅해도 데이터가 영구적으로 유지되는 키-값(Key-Value) 저장소이다.
장점
단점
localStorage.getItem()을 통해 토큰이 통째로 탈취될 수 있어, 인증 토큰 저장소로는 보안상 치명적이다.Access Token은 저장 주체에 따라 관리 방식과 트레이드오프(:하나를 얻기 위해 다른 하나를 어느 정도 포기해야 하는 관계) 가 완전히 달라진다.
서버는 "토큰을 저장하지 않아도" 되는 게 JWT의 원래 장점이고, 프론트는 "저장을 안 할 수가 없다"는 게 차이다. 서버가 저장한다면 그건 주로 강제 무효화(로그아웃, 탈취 대응)를 위한 선택적 조치이고, 프론트가 저장하는 이유는 매 요청마다 인증 정보를 실어 보내야 하기 때문에 필수적인 것이다.
| 구분 | 서버 | 프론트엔드 |
|---|---|---|
| 저장 위치 | Redis, DB 등 (선택적, 필수는 아님) | 브라우저 (인메모리 / 쿠키 / Storage) |
| 저장 목적 | 무효화(블랙리스트), 세션 통제 | 매 요청마다 인증 헤더에 실어 보내기 위함 |
| JWT의 무상태성 유지 여부 | 저장 안 하면 무상태 유지, 저장하면 사실상 세션 방식과 유사해짐 | 저장 여부와 무관하게 무상태성 유지 |
| 주요 위협 | 서버 침해 시 전체 토큰 노출 가능 (DB/Redis 해킹) | XSS(스크립트 탈취), CSRF(자동 전송 악용) |
| 통제권 | 강함 — 즉시 무효화, 강제 로그아웃 가능 | 약함 — 만료 전까지 서버가 개입 불가 |
| 확장성 영향 | 저장할 경우 매 요청마다 조회 필요 → 병목 가능 | 클라이언트 로컬 처리라 서버 부하 없음 |