그동안 많은 프로젝트에서 대부분 토큰 방식의 인증 방식을 채택하여 진행을 한 경우가 많았는데, 최근 진행한 프로젝트에서는 세션 방식의 인증을 사용해보았습니다.
카카오 OAuth2 로그인을 제공하는 Spring Security의 강력한 기능으로 백엔드에서도 적은 코드 양으로 구현을 할 수 있었지만 프론트엔드에서 토큰 관리를 따로 해줄 필요가 없다보니 너무 편해서 로그인에 거의 시간을 소모하지 않아 다른 기능에 온전한 집중을 할 수 있어 굉장히 큰 메리트로 다가왔었습니다.
하지만 서버 측에서 관리하는 세션이다보니 k8s 배포 환경에서 여러 가지 문제가 생기는 것을 볼 수 있었는데, JWT를 사용했을 때도 그러한 문제가 전혀 없던 것은 아니었기 때문에 이와 관련된 인사이트를 얻고자 올라온 글 중 하나인 "Why do many people not recommend using JWT?"를 정리하면서 JWT에 최근 제기된 이슈에 대해 한번 알아보도록 하겠습니다.
2. Why do many people not recommend using JWT?
원글의 제목은 위와 같은데 해석하자면 "왜 많은 사람들은 JWT 사용을 추천하지 않을까?" 정도일 것 같습니다.
프로젝트 기반의 온라인 강좌들을 보다보면 JWT를 사용하여 인증을 구현하는 것을 종종 볼 수 있는데요.
그러나, 진짜로 JWT는 안전할까요? 실제로 많은 사람들은 JWT 사용에 대해 경계해야 할 필요가 있다고 합니다.
3. JWT란?
JWT 공식 페이지
JWT를 한 눈에 볼 수 있는 그림이 아래에 있습니다.
JWT는 JSON Web Token의 줄임말로, 마치 JSON 데이터의 한 조각이라고 생각하면 되는데, 그 조각은 우리가 신뢰할 수 있는 누군가로부터 온 것인지를 확인하기 위해 만들어진 일종의 검증 조각인 것입니다.
검증 프로세스는 어떻게 진행될까요?
사용자가 웹 서버에 로그인을 하면, 그 웹 서버에서는 JWT를 생성하여 사용자(웹 브라우저)에게 전달합니다.
JWT는 마치 하나의 패키지처럼 동작하는데, 이 패키지 안에는 사용자를 식별할 수 있는 몇 가지 정보를 포함하고 있습니다.
이후, 사용자가 웹 서버와 통신을 할 때마다 이 JWT를 같이 실어 요청을 보내게 됩니다.
인증을 요구하는 페이지에 접근할 때마다, 사용자는 웹 서버에게 이 JWT를 제시해야 합니다.
그러면 웹 서버가 그 JWT를 받아서 이 토큰이 정말 이 웹 서버에서 발급되었는지 보장하는 시그니처를 검증하고, 사용자의 신원과 권한을 확인하기 위해 해당 토큰 내의 정보를 확인합니다.
만약 모든 것이 확인되었다면, 사용자는 그제서야 보호를 받는 페이지에 접근을 이어나가도록 허락을 받게됩니다.
4. JWT를 왜 좋지 않다고 하는 것일까?
JWT는 사용 용도에 따라서 굉장히 효율적이며, 안전하게 인증을 처리할 수 있는 기술 중에 하나로 자리잡고 있습니다.
하지만 왜 항간에는 JWT를 사용하지 않는 것을 권장한다고 하는 것일까요?
우선, 우리는 JWT를 주로 다음과 같은 작업들에서 사용됩니다:
웹 사이트 회원가입
웹 사이트 로그인
유저 클릭 / 각종 인터랙션 수행
웹 사이트는 데이터를 생성, 수정, 삭제하기 위해 유저의 정보를 사용함
위와 같은 작업들은 종종 데이터베이스 작업과 연관되는 것을 알 수 있습니다. 예를 들면,
유저가 수행하는 행동을 기록하는 작업
데이터베이스에 유저 정보를 저장하는 작업
유저가 특정 행동을 할 수 있는지 알기 위해 유저의 권한을 확인하는 작업
그럼 이제 어떠한 단점들이 있는지 단계별로 알아보도록 하겠습니다.
5. Size (사이즈)
사이즈와 관련해서는 이미 잘 알려져 있는 문제 중 하나입니다.
예를 들어, 우리가 userID(ex. cdragon)를 저장하고 싶은 경우에:
쿠키에 저장한다면, 전체 사이즈는 5바이트 밖에 되지 않을 것입니다.
JWT에 ID를 저장한다면, 사이즈가 약 51배만큼 증가합니다.
그렇기 때문에 우리에게 할당된 대역폭 부담이 늘어나는 것은 분명합니다.
6. 중복 서명(Redundant Signatures)
JWT의 주된 세일 포인트 중 하나는 JWT의 암호화된 시그니처라고 할 수 있습니다.
JWT 토큰들은 서명이 되어 있기 때문에, 수신자는 JWT가 유효하고 신뢰할 만한지 확인할 수 있는 것이죠.
하지만 지난 20년 동안, 거의 모든 웹 프레임워크는 일반 세션 쿠키를 사용하면서 암호화된 서명의 이점을 제공해 왔습니다. 실제로 대부분의 웹 프레임워크는 자동으로 쿠키에 서명(암호화까지!)하는 것을 알 수 있습니다.
즉, JWT 자체를 사용할 필요 없이 JWT 서명과 동일한 혜택을 누릴 수 있습니다. 실제로 대부분의 웹 인증 케이스에서 JWT 데이터는 세션 쿠키에 저장되기 때문에 이제는 쿠키 자체에 하나가 생기고, JWT에도 하나의 서명 레이어가 생기는 것입니다.
7. Token Revocation Issue(토큰 해지 문제)
토큰은 만료될 때까지 유효하도록 설계되어 있기 때문에 서버 쪽에서 토큰을 무효화하는 것은 쉽지 않습니다. 다음은 토큰이 위험해질 수 있는 몇 가지 사례입니다.
"로그아웃해도 실제로 로그아웃이 되는 건 아니다."
SNS에서 포스팅을 하나 올리고 로그아웃을 한 상황을 가정해봅시다. 서버에서 로그아웃이 되었다고 생각될 수 있겠지만 실제론 그렇지 않습니다. JWT는 독립적인 토큰이기 때문에 5분, 30분 또는 토큰의 한 부분에 설정된 기간이 만료될 때까지 유효할 수도 있는 것이죠. 따라서 해당 기간 동안은 누군가 이 토큰을 탈취하게 된다면 만료될 때까지 내 계정에 계속 액세스할 수 있는 문제가 생깁니다.
"Stale Data(오래된 데이터)"
사용자가 관리자에서 더 적은 권한을 가지는 일반 사용자로 다운그레이드 되는 상황을 가정해봅시다. 이 경우에도 즉시 적용되지는 않으며, 사용자는 토큰이 만료될 때까지는 관리자 권한을 계속 보유할 수 있게 됩니다.
물론, 이 경우에 큰 문제가 생기지는 않을 수 있다고 생각할 수도 있긴 하지만 의도치 않은 시스템 동작은 버그로 이어질 가능성이 굉장히 크기 때문에 좌시할 수 없는 문제이기도 합니다.
"JWT는 암호화되지 않는 경우가 있다."
중간자 공격을 수행하여 JWT를 스니핑(sniffing)할 수 있는 사람은 누구나 그 인증 자격 증명을 갖게 됩니다. 공격은 서버와 클라이언트 사이의 연결만 가로채면 되기 때문에 더 쉽죠.
요약하자면 JWT는 두 개체 간의 클레임(claim) 전송을 위한 일회성 인증 토큰으로 적합하다고 볼 수 있지만, 특히 사용자 세션 관리를 위한 장기적이고 영구적인 데이터 저장과 같은 메커니즘에는 적합하지 않을 수 있습니다.
세션 관리에 JWT를 사용하면 일련의 심각한 보안 및 구현 문제가 발생할 수 있습니다.
대신 세션 쿠키와 같은 기존 세션 메커니즘과 잘 확립된 구현이 장기적이고 영구적인 데이터를 저장하는 데 더 적합합니다. 보안이나 성능을 고려하지 않고 자체 개발 및 학습 목적으로 JWT를 사용하는 경우에는 괜찮습니다 .하지만 운영 환경을 다루는 경우에는 이러한 잠재적인 문제를 피해야 할 것입니다.