JWT 와 Session
시작하기에 앞서, 해당 글에서는 JWT에 대한 구조에 대해서는 자세하게 설명하지는 않도록 하겠습니다. 어느 정도 JWT에 대한 이해가 되신 분들이 해당 글을 읽고 어떠한 인증 전략을 가져가야 하는지 생각해보는 글이 되었으면 합니다.
Session 기반 인증
Session 기반 인증이라고 하면서 서버에서는 user에 따른 Session ID를 생성 하고 해당 Session ID를 서버 리스트에 저장을 시켜 요청이 올 때 마다 유저를 인증하는 방식입니다.
위의 Sequence Diagram (이하 SD) 을 보면 Session 기반인증의 가장 큰 특징은 서버에서 저장을 하고 있다라는 것입니다.
Token 기반 인증
토큰 기반 인증 방식은 Session과는 다르게 유저에 대한 인증 정보를 서버가 아닌 유저가 가지고 있다라는 것입니다. 마치 쿠키와 같습니다. 유저는 해당 인증 토큰을 가지고 있다가 서버에 요청을 보내면서 같이 보내고 서버는 그 토큰을 검증을 하고 결과 값을 응답하는 절차를 가지게 됩니다.
토큰 기반 인증 방식은 서버에 부하를 줄이는 형태로 되어져 있습니다. 그리고 유저에 대한 정보를 토큰 자체에 담고 있기 때문에 유저 정보를 얻기 위해 데이터베이스에 별도로 쿼리문을 보낼 경우가 적어지게 됩니다. 그리고 Token은 크게 두가지로 나뉘어 집니다.
Access Token:
서버에서 인증을 받는 토큰을 말합니다.
Refresh Token:
Access Token을 재발급하기 위해 사용되는 토큰을 말합니다.
현재 까지는 Access Token에 관련된 내용을 설명하고 있습니다. Refresh Token은 차차 설명을 하도록 하겠습니다.
Expired Time
Session ID , Token 둘 다 큰 문제점이 발생하게 되는데 그것은 바로 보안입니다. 이러한 보안적 결함을 해결하기 위해 어떠한 방식을 적용하게 되는지 알아보도록 하겠습니다.
해커가 유저의 Session ID 또는 Token을 습득 했을 때를 가정토록 하겠습니다. 아래 그림과 같이 해커는 유저의 정보를 인증할 수 있는 키들을 가지고 있으니 쉽게 서버에 접근이 가능할 것입니다.
이러한 문제점을 해결 하기 위해서는 여러 가지 방식이 있겠지만 우선 가장 간단한 방법인 새로운 Session ID와 Token을 주기적으로 발급하는 방식을 사용하게 됩니다. 그것이 바로 만료기간즉 , Expired Time을 지정하는 방식입니다.
이렇게 되면 해커는 다시 발급된 Session ID 또는 Token을 유저로부터 취득을 하여하는 번거로움이 생기게 됩니다. 하지만 이러한 방식은 근본적인 문제를 해결해주지 못하고 있다는 것을 알 수 있을 것입니다.
그리고 새로운 Session ID와 Token을 만든다는 것은 많은 컴퓨터 자원을 소비하게 되는 것으로 유저가 별로 없는 서비스의 경우 별로 큰 이펙트가 없겠지만 유저가 많은 경우에는 인증 방식에 너무 많은 자원을 사용하게 된다는 문제점이 크게 발생할 것입니다.
여기서 개발자 들은 어떠한 방식을 선택을 하였을까요?
Refresh Token
위에서 설명 하였듯이 새로운 Session ID와 Token을 다시 생성하는 상황에서는 많은 자원을 소비하게 된다고 설명하였습니다. 안타깝게도 여기서 Session ID는 이러한 문제점을 극복하지 못하고 사용이 기피하게 되어졌습니다. 반대로, Token 방식에는 Access Token을 다시 재활용이 가능하도록 하는 Refresh Token을 적용 함 으로서 이러한 문제점을 해결 할 수 있었습니다.
아래의 SD는 Refresh Token이 어떻게 작동하는 가에 대한 설명입니다. 대체로 Refresh Token을 사용하는 서버에서는 Redis를 활용하여 인증을 하고 있습니다. 해당 글에서도 Redis를 기반으로 설명하도록 하겠습니다.
대체로 Access Token의 Expired time은 Refresh Token 대비 매우 짧게 잡고 있습니다. 이러한 이유는 보안과 관련된 문제 때문이겠지요. 위의 SD 에서도 Access Token의 기간이 만료가 되었다고 한들 Refresh Token의 기간이 남아 있기에 가능한 방식입니다.
하지만 여기서도 문제가 발생하는데요. 그렇다면 해커가 access token과 refresh token을 둘 다 취하게 되는 상황에는 어떻게 되는 것일 까요?
당연하게도 해커는 유저라고 인식이 되어 인증에 성공하게 될 것입니다. 기간이 만료된 토큰도 자연스럽게 새로운 토큰을 얻어 자신이 주인인것 처럼 행동하게 될 것입니다. 참으로 복잡한 상황입니다.
Refresh Token Rotation
여기서 우리들은 컴퓨터의 성능을 좀 포기하고 Refresh Token을 주기적으로 다시 생성하는 방식을 검토하게 되는데, 그것이 바로 Refresh Token Rotation 입니다.
아마도 주기적으로 재로그인 하라는 메세지를 많이 보셨을 텐데 아마도 이러한 상황일 경우가 많다고 생각합니다. 이렇게 Refresh Token 자체도 중간에 변경이 되어서 다시 로그인 하게 되는 상황을 만들었을 경우에 보안에 대한 문제점을 좀 더 해결 할 수 있을 것입니다.
하지만 이것도 근복적인 문제를 해결하지 못하고 있습니다. 그것은 Refresh Token Rotation 되는 시간 동안 해커는 접근이 가능하다는 것이죠. 해당 문제는 완전히 해결한다는 것은 어려운 부분입니다. 그래도 해결은 하지 못한다면 차선책은 무엇인지 한번 보도록 하겠습니다.
이전에 Redis에 Key 값으로는 Refresh Token , value에는 user ID 를 입력 한 것을 기억하셔야 합니다. 해당 키 와 밸류의 위치를 변경해주면 보안에 대한 문제점을 자각할 수 있는 시스템을 구축할 수 있게 됩니다.
그렇다면 변경하게 되면 뭐가 달라지는지 알아야 하는데요. 상황은 아래와 같습니다.
- Key 가 token 인 경우 : 유저에게 단순히 재로그인만을 요청함. 즉, 해킹을 감지할 방법이 없음.
- Key 가 user ID 인 경우 : 서버가 해킹을 감지하고 유저에게 비밀번호 변경을 요청할 수 있음.
아래 그림은 정상적인 유즈케이스의 경우 Refresh Token이 재발급 되는 과정입니다.
- 유저가지 만료된 Access Token의 갱신이 필요한 과정에서 접근.
- redis에서 유저의 정보 key를 가진 ref token을 탐색.
- 유저가 보낸 ref token과 서버의 ref token 비교.
- 일치하면 access token과 refresh token 재생성.
- 새로 발급된 refresh token을 다시 저장
- 유저에게 새로운 access token과 refresh token을 전송
혹여나 refresh token을 인증하는 단계에서 검증을 실패했다고 하면 다른 누군가가 해당 아이디로 인증을 받았다는 것인데 그것을 통해 해킹여부를 확인할 수 있게 된 것입니다.
하지만 이미 말했듯이 이것은 차선책일 뿐입니다. 기존의 유저가 장기적으로 접속을 하지 않게 된다면 해커는 혼자서 계속 인증받고 있는 구조를 만들게 됩니다. 저자의 경우도 공부를 하는 중에 있어서 완벽한 내용은 아니지만 더 좋은 방식으로 문제를 해결하는 로직도 존재할 수 도 있습니다.
'Backend > Security' 카테고리의 다른 글
HTTPS, SSL/TLS (0) | 2023.07.17 |
---|---|
AccessDecisionManager, AccessDecisionVoter (0) | 2023.01.22 |
Authorization (인가), FilterSecurityInterceptor (0) | 2023.01.22 |
AuthenticationManager, AuthenticationProvider (0) | 2023.01.22 |
SecurityContextPersistenceFilter (0) | 2023.01.21 |