→들어가기
이전에도 프로젝트를 하면서 Spring Security와 JWT를 이용한 사용자 인증 시스템을 개발해 왔지만 Refresh Token을 활용하여 본적이 없기에 실제 프로젝트에 적용하기 이전에 명확한 정리가 필요한 것 같아 이번 기회를 통해 정리하고 Refresh Token을 왜 사용하여야하는지 Access Token의 문제점이 무엇인이지 다룰 예정입니다.
Access Token이란?
사용자에 대한 정보를 담고 있으며 보안 API에 접근(Access)권한을 부여 할 수 있는 토큰이다.
Refresh Token이란?
사용자 인증이 아닌 새로운 Access Token을 발급 하는 용도로 사용하는 토큰이다.
사용하는 이유는?
JWT 토큰은 사용자 정보와 권한을 담고 있는 중요한 데이터인데. 이것이 탈취 당하게 된다면 다른 사람이 인증된 사용자 인 것 처럼 접속 할 수 있고, 이에 대해 클라이언트와 탈취자를 서버에서는 구별 할 수 없기에 기간을 유효 기간을 두어야 한다.
그런데 그렇다고 Token의 유효기간을 짧게 두면 사용자가 일정시간마다 로그인을 계속 해야되는 번거로움이 생기거나, 유효기간을 길게 할수록 탈취 위험이 높아진다. 그렇기에 Access Token과 Refresh Token을 두어 사용하는 것이다.
Access & Refresh
- Access Token: 유효기간이 짧다. (ex. amazon:1시간)
- Refresh Token: 유효기간이 길다. (ex. ms: 1년)
이와 같이 평소에 api 통신을 할때는 Access Token을 사용하지만 Access Token의 기간이 만료되었을 시 Refresh Token을 사용하여 재발급하게 된다.
즉, 클라이언트와 서버가 통신하는 과정에서 탈취당할 위험이 큰 Access Token의 만료 기간을 짧게 두고 Refresh Token으로 주기적으로 재발급 함으로 피해를 최소화 하였다.
클라이언트와 서버의 동작 원리
1. 사용자가 회원가입을 한다.
2. 유효한 데이터라면 사용자의 정보가 DB에 저장된다. → 회원가입 성공
3. 사용자가 로그인을 한다.
4. Token을 사용하여 사용자 정보를 대조한다.
5. 정보가 일치하다면 Access Token과 Refresh Token을 발급한다. → 로그인 성공
6. 이 때 Refresh Token은 DB에 저장된다.
7. 이제 요청을 할 때마다 헤더에 Access Token 값을 넣어 같이 보낸다.
8. 서버에서는 Access Token의 유효성을 검사한다.
9. 유효한 토큰이라면 기대하는 응답을 보낸다.
10. 만약 Access Token의 만료시간이 다 되었다고 가정해보자.
11. 요청할 때 역시 헤더에 Access Token 값을 넣어 같이 보낸다.
12. 서버에서는 유효성을 검사할 때 만료시간이 다 되었다는 것을 확인한다.
13. 서버에서 Access Token의 만료를 알리고 Refresh Token의 응답을 요청한다
14. 클라이언트에서 만료된 Access Token과 Refresh Token을 전송한다.
15. Refresh Token의 유효성을 확인한다. → 만료기간이 지났는지 확인
16. 유효하다면 Access Token을 재발급해준다.
17. 만약 Refresh Token도 만료기간이 지났다면 다시 로그인을 해줘야 한다.
이런 과정을 거치지만 악의적인 사용자는 기간이 짧은 Access Token이라도 탈취할 수 있다. 하지만 탈취를 성공해도 짧은 만료 기간으로 인해 탈취자는 다시 탈취를 시도해야 한다. 왜냐면 JWT Token의 만료 기간은 변경이 불가능 하기 때문이라고 한다.
JWT 토큰 구조를 다시 생각해보면 Header, Payload, Signature로 되어있다. 만료 기간은 Payload에 적혀있고, Signature는 Header+Payload를 비밀키로 암호화한 것이다. 탈취자는 토큰은 계속 사용하고 싶기 때문에 Payload에 있는 만료 기간을 늘리려고 할 것이다. 그런데 Payload의 만료기간을 바꾼다고 해서 Signature가 바뀌지 않는다. Signature에서 복호화한 Payload와 변경된 Payload가 일치하지 않는 것을 비밀키를 가지고 있는 서버는 알 수 있고, 접근 권한을 내어주지 않게 되는 것이다.
이렇기에 oauth와 같은 경우 Refresh Token Rotation을 사용한다.
Refresh Token Rotation (RTR)
Access Token이 만료될 때마다 Refresh Token도 함께 교체를 해주는 것이다. 쉽게 말하면 Refresh Token을 최대한 짧게 유지하고, 재사용 불가능하게 만들어 보안을 보장하는 방법
위 그림은 PKCE를 통한 인증에서 RTR이 사용되는 방식을 나타낸 것이다. 하지만, 보편적인 원리는 PKCE가 아닌 다른 인증 플로우에서도 적용될 수 있다.
- Code Verifier와 Code Challenge을 생성한다.
- Authorization 요청을 보낸다.
- User Authorizes에서 User임이 확인되면 Authorization Code를 클라이언트에 반환한다.
- 클라이언트가 서버에 Authorization Code를 Access Token으로 교환한다(OAuth를 사용하지 않는 경우, 이 부분에서 클라이언트가 아이디와 비밀번호를 서버에 보내며 플로우가 시작된다).
- 서버는 AT1과 RT1를 반환한다.
- AT1이 만료되면 클라이언트가 새 AT1을 받기 위해 RT1을 보낸다.
- 서버는 새 AT(2)와 새 RT(2) 반환하고, RT(1)는 만료된다.
참고 사이트:
https://skatpdnjs.tistory.com/60
https://okky.kr/questions/1007579
https://engineerinsight.tistory.com/232
'spring_boot > security' 카테고리의 다른 글
Spring Security와 동작 대해서 알아보자~ (0) | 2024.04.09 |
---|---|
JWT란? (0) | 2024.04.07 |