JWT를 활용하여 Spring Security를 통해 인증/인가를 처리하는 과정을 진행하다가 AccessToken과 RefreshToken을 알게되었고! 해당 내용에 대해서 정리해보려고 한다
JWT와 관련된 글은 여기 클릭! 🖱️
JWT의 단점
"토큰을 탈취 당하면 대처하기가 어렵다"
왜냐하면, 토큰은 한 번 발급되면 유효기간이 만료될 때까지 계속 사용이 가능하기 때문!
그러면 유효기간을 짧게 잡으면 안 되나?
짧은 유효기간을 설정하면 사용자가 너무 자주 로그인을 해야 하는 문제 발생!
이를 해결하기 위한 추가적인 보안 전략 🤔
AccessToken & RefreshToken
1. AccessToken
의 짧은 만료 기간 설정
- 토큰이 탈취 당하더라도 빠르게 만료 되기 때문에 피해를 최소화!
2. RefreshToken
의 긴 만료 시간 설정
- AccessToken이 만료되었을 때, RefreshToken을 사용하여 AccessToken의 재발급을 요청
- 서버는 DB에 저장된 RefreshToken과 비교하여 유효한 경우 새로운 AccessToken을 발급하고, 만료된 경우 사용자에게 재로그인을 요청
- RefreshToken이 탈취된 경우 서버가 강제로 RefreshToken을 만료시킬 수 있기 때문에 로그아웃 처리가 쉬워짐
구체적 과정
- 로그인 인증에 성공한 클라이언트는
Refresh Token
과 Access Token
두 개를 서버로부터 받는다.
- 클라이언트는
Refresh Token
과Access Token
을 로컬에 저장해놓는다.
- 클라이언트는 헤더에
Access Token
을 넣고 API 통신을 한다. (Authorization)
- 일정 기간이 지나
Access Token
의 유효기간이 만료되었다.
4.1. Access Token은 이제 유효하지 않으므로 권한이 없는 사용자가 된다.
4.2. 클라이언트로부터 유효기간이 지난 Access Token을 받은 서버는 401 (Unauthorized) 에러 코드로 응답한다.
4.3. 401를 통해 클라이언트는 invalid_token (유효기간이 만료되었음)을 알 수 있다.
- 헤더에
Access Token
대신 Refresh Token
을 넣어 API를 재요청한다.
- Refresh Token으로 사용자의 권한을 확인한 서버는 응답쿼리 헤더에 새로운
Access Token
을 넣어 응답한다.
- 만약
Refresh Token
도 만료되었다면 서버는 동일하게 401 error code를 보내고, 클라이언트는 재로그인해야한다.
각 토큰에 저장되는 값
AccessToken
- 사용자를 식별하기 위한 아이디 값
- 클레임 내에 필요한 정보
RefreshToken
- 사용자를 식별하기 위한 아이디 값
- AccessToken을 갱신하기 위한 용도이기 때문에! 굳이 토큰 내에 다른 값을 포함할 필요가 없다
각 토큰의 저장 위치
AccessToken
1. LocalStorage
특징
- AccessToken은 JWT를 통한 Stateless 특징이 핵심이기 대문에,
클라이언트의 Local Storage
에 저장할 수 있다.
- 만료 날짜가 없이 데이터를 저장할 수 있어 브라우저를 닫거나 다시 열어도 데이터를 사용할 수 있다)
단점
- localStorage에 접근이 쉽고, 바로 토큰에 접근이 가능하다
- 공격자가 악의적인 JS 코드를 피해자 웹 브라우저에서 실행시키는 XSS 해킹 공격을 통해 해커의 악성 스크립트에 노출되어 토큰 탈취가 가능하다
2. Cookie
특징
- 토큰 값을 서버에서 쿠키에 담아 전달하면 클라이언트는 해당 쿠키를 항상 서버에 전달하게 되고, 해당 쿠키 값을 통해 인증/인가 처리를 한다
장점
- 쿠키 설정 시 httpOnly 값을 활성화해 해 준다면 네트워크 통신 상에만 토큰 정보가 들어있는 쿠키가 붙게 되어 JS로 토큰 값에 접근하는 것이 불가능해진다
- Secure 옵션을 통해 쿠키가 HTTPS로만 전송되게 하여 보안 수준을 높일 수 있다
단점
- 쿠키는 한정된 도메인에서만 사용이 된다
- CSRF 공격의 위험이 있다
RefreshToken
1. DataBase(MySQL, H2, etc)
- RefreshToken은 보통 매우 긴 시간을 설정하기 때문에 보안적으로 매우 중요하다. 따라서, 서버에서 관리해야 한다!
- 일반적으로 사용하는 데이터베이스에 저장하는 것을 고려할 수 있다
- 하지만, Spring Context 밖에 있는 Web Context에 등록된 Filter에서 영속성 관리를 하는 repository에 접근하여 엔티티를 다루는 것은 좋은 설계가 아니다
2. Redis
- 레디스는 주기억장치에 데이터를 저장하므로, DB보다 성능이 좋다
결론
- Refresh Token은
JWT 토큰의 탈취 위험을 최소화
하고, 사용자 경험
을 높이기 위해 나온 것
Access Token
의 만료 기한은 짧고, 평소 API 통신할 때 사용
Refresh Token
의 만료 기한은 길고, AccessToken을 재발급할 때 사용
Refresh Token
은 여전히 탈취 위험이 있고, Refresh Token Rotation을 통해 위험을 줄일 수 있음