Daylogs/Security

JWT 개념 이해하기

ohgyun 2021. 2. 11. 11:34

발생일: 2021.02.09

키워드: JWT, JSON Web Token, 세션 기반, stateless, Access Token, Refresh Token, 액세스 토큰, 리프레시 토큰

문제:

이번엔 인증 과정에 JWT를 사용해보기로 했다.
건너자리 B가 코드를 다 짜왔고, 자세한 설명까지 보태서 이해가 쏙 되게 공유해줬다.

 

(좋은 내용을 쉽게 이해하고 왔으니^^)
레거시만 운영해왔던 J에게도 JWT를 이용한 인증 관리를 설명해주려고 한다.

 

기존 환경과 비교해서 이해하기 쉽게 정리해봤다.


해결책:

JWT(JSON Web Token)는 인증 토큰을 정의하는 방법에 대한 표준(RFC 7519)이다.

(여러 서버 간에) 안전하게 인증 정보를 주고 받을 수 있도록, 인증 토큰을 생성하고 해석하는 방법을 규정한다.
토큰은 JSON 포맷의 정보와 이 정보의 위변조를 막기 위해 서명한 값으로 구성돼있다.

처음이라면 익숙하지 않아서 JWT를 사용하는 용도가 헷갈릴 수 있는데,
기존 세션 기반의 인증 관리 방법과 비교해보면 이해하기 쉽다.

구현 방식은 다양할 수 있지만, 이해를 위해 대략 설명해보면 아래와 같은 차이가 있다.


세션 기반 인증

클라이언트가 로그인에 성공하면,
- 임의의 토큰을 생성한 후, 토큰을 키로 인증 정보(사용자 아이디 등)를 값으로 세션에 저장
- 클라이언트에 해당 토큰을 응답

클라이언트가 토큰과 함께 요청을 보내면,
- 서버는 세션에서 해당 토큰으로 저장된 인증 정보가 있는지 확인
- 유효하다면 인증된 요청이라고 판단

구체적인 구현 방식은 다양할 것이다.
- 인증 서버를 서비스와 별도로 뒀을 수도 있고, 한 서버에서 모두 처리할 수도 있다.
- 자체 인증 서버라면 토큰을 임의로 생성했을 테고,

- OAuth를 사용해 인증 받았다면, 발급받은 액세스 토큰으로 직접 관리하거나 또는 인증 후에 별도로 관리했을 수도 있다.
- 세션에 저장하는 정보도 서비스마다 다를 테고,
- 별도의 세션 스토리지(예: 레디스)에 저장했을 수 있고, 서버의 메모리에 저장했거나 분산해서 클러스터링으로 관리했을 수도 있다.
- 클라이언트에 응답할 때엔, 쿠키로 내려줬을 수도 있고 별도의 형태로 응답했을 수도 있다.
- 클라이언트가 요청할 땐, 쿠키에 포함해서 보낼 수도 있고 헤더에 넣어서 보냈을 수도 있다.

중요한 건, 세션에 상태(토큰과 인증 정보)를 저장하고 있었다는 것이다.


JWT 기반 인증

클라이언트가 로그인에 성공하면
- 인증 정보(사용자 아이디 등)와 이 정보가 유효한지를 검증하는 값을 포함한 토큰을 생성 (예: 인증정보+유효함)
- 검증키는 서버에 별도로 저장한 비밀키로 생성
- 생성한 토큰을 (서버에는 저장하지 않고) 클라이언트에 응답

클라이언트가 토큰과 함께 요청을 보내면,
- 서버의 비밀키로 유효한 토큰인지 확인
- 토큰이 유효하다면, 토큰에 저장된 인증 정보로 처리

큰 차이점은, 세션에 상태를 저장하지 않고 토큰만 활용해 인증을 처리하는 것이다.

역시 구현 방식은 다양할 수 있으며, 중요한 특징은 다음과 같다.
- 토큰에 인증 정보가 포함되어 있고, 공개되어 있다.
- 서버에서는 비밀키로 유효성만 확인한다.
- 인증 서버를 포함한 다른 서버는 동일한 비밀키를 소유하고 있어야 한다.


주로 여러 서비스가 하나의 인증 서버를 사용하는 환경에서 사용되고,
각 서비스에서 인증을 위해 매번 인증 서버에 요청하지 않아도 되는 장점이 있다.

위에서 설명했듯이, JWT 는 이 토큰을 정의하는 방법에 대한 표준이고,
토큰을 생성하는 방법은 홈페이지에 잘 설명되어 있다.

간단하게 설명하면, 토큰은 아래처럼 정의한다.
- A.B.C 의 형태 (각 값을 dot 으로 구분)
- A = Base64Url(header). 헤더는 JSON 포맷으로, 타입과 검증 알고리즘 정보가 있음
- B = Base64Url(payload). 페이로드는 JSON 포맷으로, 인증 정보를 포함
- C = HMAC(A.B, 비밀키). 서명값
- Base64Url 은 Base64에서 +, / 를 각각 -,_ 로 대체한 것

서버에서 요청을 받으면, 토큰을 생성하는 것과 같은 방법으로 검증한다.
- A.B.C 의 토큰을 받으면,
- HMAC(A.B, 비밀키) = C 와 동일한지 확인

더불어, 토큰의 추가적인 관리를 위해 일반적으로 payload 에는 발급자, 발급시간, 만료시간 정보를 포함한다.

JWT에 대한 자료는 워낙 많아서,
개념과 용도를 파악했다면 다른 자료를 검색해서 보면 상세히 이해될 것 같다.

 

 

논의:

 

발급한 토큰의 보안과 관련해 몇 가지 선택적으로 관리해야 할 사항이 있다.

이건 다음 포스트에...

 

 

참고:

- JWT 홈페이지의 토큰 구성 예제: jwt.io/#debugger-io

반응형