들어가면서
이번 프로젝트에서 Spring Security를 맡게되었고 인증&인가에 대해 배우게 되었다. 그 중 JWT를 사용하여 인증&인가를 진행했는데, 이때 Access Token과 Refresh Token의 차이와 역할에 대해 배우게 되었다.
해당 글에서는 특히 Refresh Token이 왜 필요한지, 보안을 위해 어떻게 사용될 수 있는지에 대해 알아볼 예정이다.
Refresh Token이 필요한 이유
JWT은 유저의 신원이나 권한을 결정하는 정보를 담고 있다. Access Token, 즉 단일 토큰만 발행한 경우에는 다음과 같은 로직을 가진다. JWT 토큰 인증방식은 비밀키로 암호화를 하기에서버와 클라이언트는 JWT를 통해 안전하게 통신한다.
- 로그인 성공시 서버측에서 클라이언트로 JWT를 발급한다.
- 권한이 필요한 모든 요청에서는 클라이언트에서 서버측으로 JWT를 전송해서 인증한다.
그러나 토큰을 탈취되었을 경우에는 문제가 생긴다. 토큰을 탈취한 사람이 이 토큰을 이용해서 자유롭게 인증을 통과할 수 있기 때문이다. JWT는 Stateless 상태이므로 서버에서 상태를 관리하지 않기에 서버에서는 토큰의 상태를 제어할 수 없다.서버는 토큰의 주인을 알아볼 수 없다. 또한 토큰이 탈취당하면 그 토큰이 만료되기 전까지 속수무책이므로, 토큰에 유효기간을 두어 탈취에 대한 위험성을 낮추어야 한다.
그러나 유효기간을 짧게 두면 로그인 유지 시간이 그만큼 짧아지기에 사용자 편의성 측면에서 좋지 않고, 유효기간을 길게 두면 보안적 측면에서 좋지 않다. 따라서 토큰을 유효기간이 다른 2개의 토큰, Access와 Refresh로 나누어 관리한다.
- Access Token : 사용자에 대한 정보를 담고 있어 서비스에 접근 할 수 있도록 한다 => 유효기간이 짧다.
- Refresh Token : 이 자체에는 별다른 정보가 없지만, Access Token이 만료되었을 때 서버에서 이를 확인하고 새로운 Access Token을 발급해 준다. 즉, 재발급 용도로만 사용된다 => 유효기간이 길다.
Refresh Token의 사용법
Access Token과 Refresh Token의 인증 플로우에 대해 알아보자.
1. 사용자가 로그인을 하면 DB를 통해 사용자가 존재하는지 확인하고, 존재한다면 Access와 Refresh Token을 발급한다.
2. 인증이 필요한 활동(게시판 CRUD 등)에 Access Token을 헤더에 포함해 보내고, Access Token 검증을 통해 유효성을 검사하고 유효할 경우 데이터를 응답한다.
3. Access Token 검증 시 유효기간이 만료되었다면, Refresh Token을 보내 재발급 요청을 한다. Refresh Token의 유효성을 검사하고 새로운 Access Token을 발급한다. 이때, 기존 Access Token은 제거해야 한다.
Refresh Token이 탈취되는 경우
1. Refresh Token Rotate
Access Token을 갱신하기 위한 Refresh Token 요청 시 서버측에서 Refresh Token도 재발급을 진행하여 한 번 사용한 Refresh Token은 재사용하지 못하도록 한다. Refresh Token을 최대한 짧게 유지하고, 재사용 불가능하게 만들어 보안을 보장하는 방법이다.
2. Access Token & Refresh Token 저장위치 고려
후보지로는 로컬/세션 스토리지와 Http Only 쿠키가 있다. 각자 특성에 맞게 Access와 Refresh Token을 저장해야한다.
- 로컬/세션 스토리지 : 단일 토큰 시에는 로그인 성공 시 받아온 토큰을 세션 스토리지에 저장하고, 요청을 보낼 때 자바 스크립트로 꺼내서 보았었다. 그러나 이 경우 XSS(Cross Site Scripting) 공격에 취약하다.
- HttpOnly 쿠키 : Http Only 옵션과 secure 옵션을 걸면 쿠키를 탈취당할 위험을 막고, 자바스크립트로 쿠키 값을 취득하는 것도 막을 수 있다. 그러나 CSRF(Cross-Site Request Forgery) 공격에 취약하다.
- Access Token : 로컬/세션 스토리지에 저장. XSS 공격을 막기 위해, Access Token을 자바스크립트의 private 변수로 저장한다. 이렇게 되면 XSS 공격, CSRF 공격을 모두 막을 수 있다. 그러나 새로고침을 하면 변수가 날아가기 때문에, 이 경우 Refresh Token을 가지고 Access Token을 발급받는 API가 필요하다.
- Refresh Token : HttpOnly 쿠키에 저장. Refresh Token은 Access Token을 재발급 받는 요청 외에는 접근 할 수 없기 때문에 쿠키에 저장해도 된다. 이때 방어를 위해 Refresh Token Rotatate를 적용할 수 있다.
마무리
아직 security에 대해 알길이 멀지만, Access와 Refresh Token에 대해서는 확실히 알게 된것같다. 앞으로도 시큐리티를 정복하기 위해 열심히 해야겠다.
'Spring' 카테고리의 다른 글
Feign 사용기 (7) | 2024.09.08 |
---|---|
상속을 이용해 Entity 구성하기 (0) | 2024.09.08 |
동시성 제어 (1편) (0) | 2024.09.01 |
간단하게 알아보는 Spring Cloud Config (0) | 2024.09.01 |
븟츠의 동시성 이슈 해결 방법 (0) | 2024.09.01 |