JWT 토큰 인증 방식 살펴보기

JWT Token 이란 무엇인가?

Facebook, Github, Google 등의 외국계 회사들의 Open API 를 통한 회원인증을 구현해봤다던가 혹은 카카오 API 등을 이용해본적이 있다면 한번쯤은 JWT Token 에 대해서 들어봤을 것이다. JWT Token 은 JSON Web Token 의 약자로서, 자체의 토큰은 Base64로 인코딩한 평범한 String 으로 이루어져 있다. 이 JWT Token 은 access token 을 만들기 위해 사용된다. 물론 여기에서 이야기 하는 access token 이란 단순하게 우리가 분류하는 자원에 접근하는 access token 만을 이야기 하는 것이 아니라, 권한/인증에 대한 token 을 말한다. JWT Token 은 그 자체만으로도 권한과 인증의 역할을 가질 수 있다.

JWT Token 의 구조

JWT Token 은 위에서 말했듯이 평범한 String 인데 어떻게 권한/인증을 체크할 수 있을까? JWT Token 자체를 보면 아래와 같이 마침표를 기준으롤 3가지 영역으로 나뉘어져 있다.

/images/jwt/jwt01.png

각자의 영역은 사진과 같이 각자의 영역이 있다. 아래의 사진은 위의 JWT Token 을 Decoding 했을 때의 결과다.

/images/jwt/jwt02.png

Header 영역

/images/jwt/jwt03.png

Header 영역에는 해당 Token 에 대한 유형알고리즘에 대한 정보가 포함되어 있다. 위의 Token 은 JWT 공식 홈페이지 에서 가져온 Token 으로서 Token 의 알고리즘은 HS256 이고, 유형은 JWT 이다. 알고리즘은 HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512 등 각 언어별로 지원하는 알고리즘이 있으니 공식 홈페이지에서 확인해서 선택하면 된다.

Payload 영역

/images/jwt/jwt04.png

Payload 영역은 기본적인 유저에 대한 정보와 함께 추가한 유저의 정보가 포험되어 있다. JWT Token 에서는 이미 정해져있는 이름을 가진 아래의 7개에 대한 정보를 담을 수 있다.

  1. iss: Token 발행자(Issuer) 으로서 해당 필드는 문자열 혹은 URI 로 이뤄지면 선택사항이다.
  2. sub: Token 의 제목 (Subject) 으로서 해당 필드의 값은 문자열 혹은 URI 로 이루어져 있다. 해당 값은 전역적으로나, 발행자 범위에서 유일한 값이어야 한다.
  3. aud: Token 의 대상자 (Audience) 로서 해당 값에 대한 인증이 이뤄지지 않으면 해당 Token 을 이용한 접근이 거부 된다. 해당 필드는 문자열 혹은 URI 로 이루어져 있다.
  4. exp: Token 의 유효한 날짜 정보(Expiration time) 으로서, 해당 Token 을 가지고 요청을 했을 때 현재의 시간을 지났다면 해당 Token 을 이용한 접근이 거부된다. 일반적으로는 몇 분 이내로 설정을 하며 해당 값은 숫자로만 이루어져야 한다.
  5. nbf: Token 의 유효 시작 날짜 정보 (Not before) 으로서, 해당 Token 을 이용하려면 현재의 시간이 이 정보에 기재된 시간과 같거나 지났어야 한다. exp 와 마찬가지로 일반적으로는 몇 분 이내로 설정하며 해당 값은 숫자로만 이루어져야 한다.
  6. iat: Token 의 발행된 날짜 정보(Issued At) 으로서, JWT 이 발행된 시간에 대한 정보를 담고 있다. 위의 exp 혹은 nbf 와 마찬가지로 숫자로만 이뤄져야 한다.
  7. jti: Token 의 고유 식별자(JWT ID) 로서, 해당 값은 고유한 식별자에 대한 값이 할당되어야 한다. 해당 값은 대소문자를 구별하는 문자열로 구성되어져 있다.

Signature 영역

/images/jwt/jwt05.png

Signature 영역은 각 Header, Payload 에 해당 하는 정보와 서명키에 대한 정보가 들어가져 있다. 이 영역은 Header 에서 지정한 알고리즘으로 만들어져 있으며, 인증에 대한 정보 확인 및 변조 여부를 확인하는데 사용된다.

JWT Token 의 특징

JWT Token 은 다음과 같은 특징이 있다.

JWT Token 은 Stateless 하다

기존의 웹 어플리케이션은 대체적으로 세션 기반으로 인증 처리를 많이 구현을 했다. 세션을 이용하면 단점이 어딘가에 그러한 세션 정보를 저장을 해야한다는 것이다. 그러한 정보는 대체적으로 서버의 메모리 에 저장을 하는 경우가 많다. 서버의 메모리에 저장을 하고 있다가 갑자기 유저의 수가 늘어난다면 여기에서 또 서버를 증설할 것이다. 그렇게 되면 문제점이 두가지가 생긴다. 첫번째는 늘어난 수만큼 서버의 메모리를 계속 사용을 해야한다는 점이 있을 것이고, 두번째는 세션 정보가 서버 간에 공유 되지 않는다는 점이다.

/images/jwt/jwt06.png

위의 사진과 같이 어떠한 유저가 A 서버로 접속해서 로그인을 했다고 가정해보겠다. 로그인을 하면 A 서버에는 해당 유저에 대한 세션 정보를 저장할 것이다.

/images/jwt/jwt07.png

그러다가 만약 유저가 B 서버로 접속이 됐다면 B 서버에는 세션 정보가 없어 로그인일 풀릴 것이다.(로드밸런싱에 대한 개념은 위 주제와는 벗어남으로 추후 따로 설명하도록 하겠다.) 그렇게 되면 로그인을 하고 나서도 계속 로그인을 하라고 나올 것이다. 실제 필자도 위의 경우에 직면한 적이 있었다. 물론 그러한 해결 방안으로는 Sticky session 을 이용했지만, 사실 근본적인 해결방법은 아니었다. (여기에서의 관점은 session 이 주제가 아님으로 따로 이야기하지 않고 넘어가도록 하겠다.) 물론 위와 같은 방법을 우회하는 방법도 있다. 자체 세션 서버를 따로 두는 것도 하나의 방법일 수 있다. 하지만 그렇게 몰아넣는 것 역시 서버에서는 부하가 걸릴 수 있다. 이와 같은 stateful 한 방법은 요즘과 같이 서버를 스케일 아웃(Scale-out)할 때 문제가 생길 수 있다. 이러한 stateful 과 상반되는 개념이 stateless 이다. JWT Token 은 서버 입장에서 요청을 받았을 때 그때그때 인증과 권한 체크를 하기 때문에 세션 처럼 따로 저장할 필요는 없다. 위와 같이 A 서버로 접속했다가 B 서버로 요청을 한다고 해도 문제 생길 것이 없다. 쉽게 이야기 해서 수평으로 쉽게 확장이 가능하다는 의미가 된다.

JWT Token 은 무결성이 보장된다.

공식 홈페이지에 메인에서 테스트를 해보면 예시로 보여주고 있는 JWT Token 의 secret 키를 하나라도 입력을 하게 되면 JWT Token 에서 Signature 영역의 글자가 바로 바뀌는 것을 알 수 있다. 이처럼 JWT Token 은 변조가 되었을 때, 바로 알아차릴 수가 있다.


출처

현재 이커머스회사에서 frontend 개발자로 업무를 진행하고 있는 Martin 입니다. 글을 읽으시고 궁금한 점은 댓글 혹은 메일(hoons0131@gmail.com)로 연락해주시면 빠른 회신 드리도록 하겠습니다. 이 외에도 네트워킹에 대해서는 언제나 환영입니다.:Martin(https://github.com/martinYounghoonKim
Withinnovation 회사를 떠나며
하노이 탑 알고리즘