현재 진행 중인 사이드 프로젝트 모카콩(https://github.com/mocacong/Mocacong-Backend)에서는 기존엔 Access Token 하나만 가지고 로그인 처리를 진행했었습니다. 그러나 유효시간이 짧은 Access Token 특성 상, 빈번하게 로그인 요청을 수행해야 했으며 이는 불편함을 초래하였습니다.
이에 따라 보안적인 측면을 고려하며 로그인 유효시간을 늘릴 수 있는 Refresh Token을 도입하기로 결정했습니다.
1. Refresh Token의 필요성
일반적으로 서비스에서 회원 인증을 위해 많이 사용되는 JWT(Json Web Token) 방식을 모카콩 프로젝트에서도 도입했습니다. 하지만 사용자 인증을 위한 Access Token의 유효시간은 약 30분으로 설정되어 있었습니다. 이로 인해 사용자는 30분이 지날 때마다 모카콩 서비스에 접근하기 위해, 매번 로그인을 수행해야 했습니다. 이러한 불편함을 없애기 위해 단순히 Access Token 유효시간을 무한정 늘릴 수는 있으나 JWT의 가장 치명적인 단점을 생각하면 이는 지양해야 하는 방법입니다.
1) JWT의 단점
JWT를 암호화하더라도 해커가 악의적인 의도를 갖고 토큰을 탈취하여 payload 영역의 데이터를 확인할 수 있습니다. 또한, JWT는 한 번 발급되면 데이터베이스에서 별도로 관리되지 않기 때문에 유효기간이 지날 때까지 계속 사용할 수 있습니다.
따라서 JWT로 이루어진 AccessToken의 유효시간을 무한정 늘리는 것은 보안적으로 취약한 상황을 초래할 수 있습니다.
2) Refresh Token
이러한 JWT의 단점을 고려하여, 보안을 생각하여 Access Token의 유효시간은 짧게 유지하되 사용자가 매번 로그인해야하는 불편함을 줄이기 위해 나온 것이 Refresh Token입니다.
Refresh Token은 Access Token 갱신하기 위해 필요한 토큰입니다. 일반적으로 Refresh Token은 약 2주에서 1달 정도의 유효시간을 갖고 있으며, 이 기간 동안 사용자는 Refresh Tokend을 사용하여 여러번 Access Token을 재발급받을 수 있습니다.
3) Refresh Token을 도입한 경우에서의 인증 로직
만약 Refresh Token 없이 Access Token으로만 사용자 인증을 수행했다면 4-2까지 수행되고 Access Token 유효시간이 지났다는 예외를 받았다면 다시 1번으로 돌아가 로그인을 수행해야 하는 번거로움을 겪습니다.
Refresh Token을 도입한다면 Access Token의 유효시간이 지나더라도 로그인 요청없이 Access Token을 재발급 받을 수 있습니다.
Access Token을 재발급하기 위해 처음 로그인 요청 시 받은 Refresh Token을 서버에게 전송합니다. 이때 서버는 해당 Refresh Token이 유효한지 확인하고 유효하다면 Access Token을 새로 발급합니다. 물론, Refresh Token도 유효시간이 지나면 다시 처음으로 돌아가 로그인을 수행해야 하지만, 일반적으로 Refresh Token의 유효시간은 14일에서 한 달로 설정되기 때문에 30분마다 로그인 요청을 수행했던 도입 전의 상황과 비교하면 훨씬 번거로움이 적어집니다.
2. Redis
클라이언트에서 보낸 Refresh Token의 유효성을 확인하기 위해서는 서버 측에서 리프레시 토큰 정보를 저장할 수 있는 곳이 필요합니다. 일반적으로 DB에서 저장되는데 모카콩 프로젝트에서는 인메모리 방식의 데이터베이스, Redis에서 Refresh Token을 관리하기로 결정했습니다.
1) Redis
데이터베이스의 종류는 크게 2가지로 나뉩니다.
① RDB (관계형 데이터베이스)
- SQL 언어를 사용하여 접근하며 데이터는 테이블 형태로 구조화됨
- 주로 HDD나 SSD 같은 보조기억 장치에 데이터를 저장
② NoSQL
- HDD나 SDD같은 보조기억 장치에 key-value, 문서, 그래프의 방식으로 데이터를 저장
- 데이터의 형식이 따로 정해져있지 않아 유연한 데이터 구조를 가짐
여기에 더해 In-Memory DB가 있는데 NoSQL 방식에 속하는 데이터베이스이며, 데이터를 디스크 대신 메모리에 저장하여 I/O의 성능을 높입니다.
Redis는 Key-Value 형태로 데이터를 저장하는 In-Memory 기반의 NoSQL DBMS입니다. Redis는 데이터의 휘발성 문제를 극복하기 위해 데이터를 디스크에도 따로 저장하여 서버가 종료돼도 데이터를 보존할 수 있습니다.
2) Redis 도입 계기
Redis는 인메모리 상태에서 데이터를 처리하기 때문에, 다른 데이터베이스들보다 빠르고 가볍다는 장점이 있습니다.
레디스를 처음 사용한다면 설정을 위한 부가적인 추가 작업이 필요하지만, 모카콩에서는 조회 성능을 향상시키기 위해 레디스를 먼저 도입한 바가 있기 때문에 이미 완료된 상태였습니다. 그렇기에 리프레시 토큰을 도입할 때 레디스를 사용 안할 이유가 없었습니다. (무엇보다 레디스 공부해보고 싶었습니다...ㅎㅎ)
3. Redis를 통한 Refresh Token 관리 로직 요약
Redis를 통한 Refresh Token 관리 로직은 개발자마다 약간씩 다르게 구현할 수 있으나 현재 모카콩에서는 위와 같은 로직으로 구현했습니다.
유효한 RefreshToken이더라도 AccessToken을 무한정 재발급해주면 위험합니다. 그렇기에 Redis에서 리프레시 토큰의 유효성을 검증하기 전에 먼저 사용자의 AccessToken이 만료됐는지 확인합니다. 만료가 되었다면 Redis에 사용자가 보낸 RefreshToken이 유효한지 검증 요청을 보내고 Redis에 해당 RefreshToken의 정보가 남아있다면 아직 RefreshToken의 유효기간이 지난 것이 아니므로 서버에게 유효함을 알려줍니다. 서버는 해당 RefreshToken이 유효함을 확인하면 사용자에게 새로운 AccessToken을 재발급해줍니다.
이렇게 Redis를 통해 RefreshToken을 관리하고 AccessToken을 재발급한다면 AccessToken의 유효기간을 무한정 늘리는 방식보다 훨씬 보안이 강화됩니다.
실제 구현 방식에 대한 자세한 내용은 다음 글에서 설명하겠습니다.
'백엔드 개발일지' 카테고리의 다른 글
[Spring/AWS] Pre-Signed Url을 이용하여 S3로 파일 업로드하기 (feat. NCP) (0) | 2023.12.25 |
---|---|
[Spring] Redis를 통한 Refresh Token 도입기 (2) (1) | 2023.12.18 |
[Spring] Code Coverage 측정을 위한 JaCoCo 적용하기 (0) | 2023.12.04 |
[Spring] 멀티 모듈 프로젝트 도입하기 (3) | 2023.11.20 |
[JPA] 코멘트 신고 기능 도입 및 벌크 연산과 배치 작업을 통한 기간 정지 구현 (0) | 2023.07.22 |