JWT를 선택한 이유(+Redis)

Why did I choose jwt?

HTTP의 Stateless한 특징 때문에 인증을 관리하기 위한 방안(Session, JWT)이 필요하다. Session과 JWT를 간단히 알아보고 프로젝트에 왜 JWT를 적용하게 되었는지 알아보자.

Session

Session 같은 경우 토큰방식보다 보안에 강하다는 장점이 있지만 단점으로 서버의 확장성이 떨어지고 서버의 자원(세션을 저장할 공간)이 많이 필요하다. 그리고 멀티 디바이스 환경에서 처리에 신경써줘야 할 부분이 생긴다.

JWT(Json Web Token)

JWT는 인증에 필요한 정보들을 암호화 시킨 토큰을 뜻하며 Header, Payload, Signature 3부분으로 이루어지게 된다. Json 형태인 각 부분은 Base64Url로 인코딩되어 표현된다. 각 부분을 이어 주기 위해 .구분자를 사용하여 구분한다.

Base64Url은 암호화된 문자열이 아니고 같은 문자열에 대해 항상 같은 문자열을 반환

Header(헤더)

헤더는 알고리즘 방식인 alg와 토큰의 타입인 typ으로 구성된다.

{
  "alg": "HS256",
  "typ": "JWT
}

Payload(페이로드)

서버에서 보낼 데이터(sub, name, iat)

Signature(서명)

서명은 Base64방식으로 인코딩한 Header(Encoded Header), Payload(Encoded Payload)를 SECRET KEY를 이용해 Header에서 정의한 알고리즘으로 해싱 하고, 이 값을 다시 Base64Url로 인코딩하여 생성

장점

세션/쿠키는 별도의 저장소 관리가 필요하지만 JWT는 발급한 후 검증만 하면 되기 때문에 따로 저장소가 필요하지 않다. 이는 Stateless한 서버를 만드는 입장에서 큰 강점인데 서버를 확장하거나 유지, 보수하는데 유리하다.

단점

이미 발급된 JWT에 대해 돌이킬 수 없다. 세션/쿠키 같은 경우 만일 쿠키가 악의적으로 사용되면 해당 세션을 지워도 된다. 하지만 JWT는 한번 발급되면 유효기간이 만료될 때 까지 계속 사용가능 하기 때문에 위험하다. 또한 세션/쿠키 방식에 비해 JWT의 길이는 길기 때문에 인증이 필요한 요청이 많을 수록 서버의 자원낭비가 발생할 수 있다.

우리는 JWT를 왜 선택하게 되었을까

우리는 Session 방식대신 JWT를 선택하게 되었다. REST API의 Stateless한 특성에 JWT가 좀 더 부합하는 것 같았고 웹뿐 아니라 모바일도 생각하고 있었기 때문에 처리를 더 간소화하고 앞으로의 확장성을 생각해 선택하게 되었다. 보안같은 경우 RefreshToken을 추가하여 추가적으로 보완하기로 생각했다.

Refresh Token: Access Token을 재발급해주는 용도의 토큰. Access Token으로만 진행할 경우의 문제점은 유효기간을 길게할 경우는 탈취당하면 그 긴 시간동안 정보 탈취, 유효기간을 짧게하면 사용자가 로그인을 계속해야되는 번거로움이 있다. 그래서 나온게 Refresh Token으로 Access Token의 경우 유효기간을 짧게 잡고 Refresh Token을 길게 잡아서 Access Token의 기간이 다 되어도 Refresh Token으로 사용자는 로그인 없이 다시 Access Token 재발급 가능

RefreshToken에 대한 고찰

JWT의 구성방식이나 저장장소에 대해 정말 많이 고민하고 찾아본거 같은데 정말 다양했던 것 같고 그에 따른 의견도 정말 다 달랐다. 어느 것이 제일 뛰어나다고 할 수 없었고 다들 trade off가 있었던 것 같다. 우리 같은 경우 RefreshToken은 쿠키에 저장하는걸 선택했고 HTTPOnly와 Secure 옵션을 사용해 CSRF 공격에 대비하고 추가적으로 리프레쉬 토큰값은 노출시키고 싶지 않았기 때문에 실제 리프레쉬 토큰값에 해당하는 id(random uuid)값을 쿠키에 저장하게 하였다.

+Redis

서버에서는 RefreshToken을 Redis라는 In Memory에 저장하게 되었다. 결국 API를 사용하는데 Access Token이 가장 중요하기 때문에 이 Access Token을 재발급 해주는 토큰(RefreshToken)을 읽고 쓰는 데이터베이스가 조금 더 빠르면 좋을 것 같아 생각하게 되었고, Refresh Token 같은 경우 일정 시간 뒤에 삭제를 해야 하는데 일정 시간 뒤 자동으로 삭제되는 TTL(TimeToLive) 기능이 지원되어 잘 맞을 것 같았다. 휘발성이라는 단점은 Refresh Token 같은 경우 휘발되어도 큰 문제가 되지 않는 정보라 상관없을 것 같다.


참고: https://jwt.io/

*틀린 부분이 있으면 언제든지 말씀해 주시면 공부해서 수정하겠습니다.


© 2022. All rights reserved.

Powered by 애송이