본문 바로가기
Programming/DevOps, Tools

JWT (JSON Web Token) 도입기 - JWT는 만능해결사인가

by kghworks 2023. 3. 2.

jwt.io tokens created count

 

 

목차

  • JWT 토큰을 도입한 계기
  • JWT의 문제점
  • 앞으로의 개선방향

 

 실무에서 JWT를 도입했던 일화를 소개합니다. JWT의 개념, 소스 구현 등은 구글링 하면 예제들과 함께 자세히 나오니 해당 레퍼런스들을 참고하시기 바랍니다.

 


JWT 토큰을 도입한 계기

 별도의 세션저장소 (ex. Redis)를 두지 않은 경우 세션은 WAS에 부하를 줍니다. 일반적으로 이 문제에 직면한 뒤 세션 저장소를 별도 구축하거나 JWT 도입을 고민하는데요. 그러나 제가 실질적으로 실무에서 JWT를 도입하게 된 계기는 이원화된 서버의 세션 정합성 문제였습니다.

 

 제가 맡은 레거시는 서버 부하 분산을 위해 was를 2대 이상으로 세팅하였으나, 실제 세션 데이터는 클러스터 혹은 별도의 세션 저장소 구축은 되어있지 않았습니다. 따라서 제가 선택할 수 있는 아래 3가지 옵션이 있었습니다.

 

  1. was 세션 클러스터링 설정
  2. Redis 세션 데이터베이스 구축
  3. JWT token 도입

 

 저는 결론적으로 3번을 도입하게되었습니다.

 

 1번은 안 하게 된 이유는 Redis의 존재를 알고 나서 1번이 굉장히 후져 보였습니다. 세션 정합성 문제를 해결하기 위한 즉각적인 조치는 될 수 있었습니다만, 세션 디비를 구축하지 않고, 실시간으로 세션 데이터를 클러스터링 한다는 게 was 오버헤드라고 보았습니다. 2번을 알게 된 이상 1번은 쓸 이유가 없는 거죠.

 

 2번은 궁극적인 해결책이 될 수도 있겠다고 생각했지만, 제반 작업이 부담스러웠습니다. Redis를 설치하고, Redis 연동 소스로 프로젝트 소스를 전체 수정하는 것이 일정상 힘든 상황이었습니다.

 

 그래서 JWT 토큰을 도입했습니다. 토큰에 저장하는 값이 1차적으로 해시되어서 저장되나, 복호화가 가능한 문자열이기 때문에 민감한 정보가 있으면 안 되었습니다. 제가 개선할 레거시의 경우 그러한 민감 정보는 없었기에 적합하다 판단했습니다.

 


JWT의 문제점

 

  • token value 노출, 누구나 복호 가능
  • token 공간에 따른 request 부하

 

 기본적으로 JWT는 클라이언트에게 정보를 저장합니다. (localStorage or Cookie) 클라이언트에 저장된 정보는 탈취뿐 아니라 애초에 개발자도구를 열면 너무 쉽게 token value가 노출되니 개발하면서 이것 참 위험하기도 하겠다.. 생각이 듭니다. 보안에 민감한 사이트나, 정보 자체가 민감하다면 JWT token에는 많은 정보를 담으면 안 될 것 같습니다. 언제든 token 값만 확보하면 복호화가능하기 때문이죠.

 

 참고로 MDN에선 애초에 저장소를 쿠키보다는 웹 스토리지 (localStorage, sessionstorage)를 추천합니다.

 

과거엔 클라이언트 측에 정보를 저장할 때 쿠키를 주로 사용하곤 했습니다. 쿠키를 사용하는 게 데이터를 클라이언트 측에 저장할 수 있는 유일한 방법이었을 때는 이 방법이 타당했지만, 지금은modern storage APIs를 사용해 정보를 저장하는 걸 권장합니다. 모든 요청마다 쿠키가 함께 전송되기 때문에, (특히 mobile data connections에서) 성능이 떨어지는 원인이 될 수 있습니다. 정보를 클라이언트 측에 저장하려면 Modern APIs의 종류인 웹 스토리지 API (localStorage와 sessionStorage) 와 IndexedDB 를 사용하면 됩니다.

*출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies

 

 

  저장된 token 문자열이 너무 깁니다.  request 시 너무 긴 문자열은 통신부하를 줄 수밖에 없는데요. 게다가 token이 로그인 사용자 정보라면 이 문자열을 매 request마다 복호하고, 검증하는 비즈니스로직이 들어가게 됩니다.

 

 이러한 문제들로 인해 백엔드 API와 협의가 가능한 상황이라면, 적절하게 토큰에 저장할 값과 백엔드에서 검증하면서 꺼낼 값을 분산하여야 합니다. 안 그러면 was의 세션 대비 비즈니스 로직이 더 복잡하거나, request 부하가 더 심하여 결론적으로 성능이 저하됩니다.

 

 그리고 Refresh token을 도입하여 access token의 생명주기 자체를 짧게 가져가야 합니다. jwt는 어디에 저장했든 공격 위험에 노출된다는 것을 염두하셔야 합니다. 따라서 jwt 자체에 민감한 정보는 저장하시면 안 됩니다. token value를 긁어서 복호화했을 때 사용자 비밀번호, 전화번호 등이 노출되면 안 되겠죠.

 

 


앞으로의 개선방향

 궁극적으로는 JWT토큰에 데이터를 저장하되 민감한 데이터는 세션에 저장하는 형식으로 개선해 나가야 되겠습니다. (실무에서도 은행권에서는 세션과 JWT를 혼합하여 사용하는 곳도 있다고 하네요)

 

 JWT 에는 공격 (혹은 노출)에도 문제 되지 않는 데이터들을 저장하되, 민감한 정보는 세션에 저장합니다. 단, 세션은 별도의 세션 저장소 (메모리 기반 DB ex. Redis)를 구축함으로써 다중화된 서버의 세션 정합성, WAS 부하 등의 문제를 해소할 수 있을 것 같습니다.

 

 


참고

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

 

Window.localStorage - Web APIs | MDN

The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin; the stored data is saved across browser sessions.

developer.mozilla.org

https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies

 

HTTP 쿠키 - HTTP | MDN

HTTP 쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각입니다. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이

developer.mozilla.org

 

댓글