코딩은 내일부터

JWT 그게 뭔데. 본문

우아한 테크 코스(우테코)/우테코 공부

JWT 그게 뭔데.

zl존 비버 2023. 8. 11. 22:11
728x90

이번 프로젝트에서 JWT쪽을 맡게 됐다.

이번 포스팅에서는 JWT과 JWT을 적용하는 과정을 설명할 예정이다.

 

JWT을 적용한 이유

이번 프로젝트에서 JWT를 적용한 이유는

  1. JWT는 토큰 자체에 필요한 정보를 포함하고 있어 서버 측에서 별도의 상태를 유지하지 않아도 된다.                                              (이로써 서버는 요청마다 토큰을 검증하고 사용자 신원을 확인할 수 있어 세션 관리나 DB의 부담을 줄일 수 다.(accessToken의 정보 만으로 사용자 인증을 할 수 있어서)
  2. JWT는 토큰은 매 요청마다 사용자 데이터베이스 등과의 통신 없이 빠르게 인증을 수행할 수 있다.

따라서 서버 부하를 줄여준다.(access가 만료되고 refachToken의 정보를 확인 할 때 DB에 접근하니까!)

 

이러한 이유로 JWT를 적용하기로 결정했다.+ 학습목적

이렇게 JWT를 결정됐는데 나는 JWT가 뭔지 모르고 있어서 JWT에 대해 공부해보았당.

 

JWT가 뭔데?

먼저 JWT는

header,payload,signatuer로 구성되어있고,

각각의 구성요소가 점(.)으로 구분되어있는 형태이다.

header.payload.signature

그러면 이제 각각 header,payload,signatue의 대해 알아보겠다.

 

 

 

 

header는 일반적으로 토큰의 타입그리고 어떤 알고리즘을 사용됐는지 나타내 준다.

 

옆에 보이는 예시는 타입이 JWT이고,

알고리즘을 HS256을 사용하고 있다고 나타낸 것 이다.

 

 

 

 

 

payload는 토큰에 담는 클래임(Claim)정보를 포함하고 있다.

 

Payload 에 담는 정보의 한 ‘조각’ 을 클레임이라고 부르고,

이는 key / value 의 한 쌍으로 이뤄져있다. 토큰에는 여러개의 클레임 들을 넣을 수 있습니다

옆에 예시는 사용자의 ID와 토큰의 발급 시간,토큰의 만료 시간 이렇게 구성했다.

 

 payload에 표준스팩
  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
  • nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
  • iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
  • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.

 

 

 

마지막으로 signature

header의 인코딩값(base64)과,

payload의 인코딩값(base64)을 합친 후

정의한 비밀키로 해쉬알고리즘을(HS256) 통해 해서 생성합니다

 

 

 

아래 사진은 완성된 JWT토큰의 형태입니다.

완성된 JWT토큰

 

JWT+1 강

이렇게 JWT가 무엇인지 공부를 했는데 공부하는 도중에 JWT의 강화버전인

Access토큰과 Refresh토큰 방식이 좋다는 말을 듣고

AccessToken과 RefreshToken의 대해 알아봤다.

 

 

Access토큰이 뭐고 Refresh토큰이 뭐야??

JWT 하나로 인증을 하다보면 제 3자에게 탈취당할 경우 보안에 취약하다.

그래서 토큰의 유효기간을 짧게 가져가면 계속 토큰을 발급해줘야하고,

유효기간을 늘리면 보안에 취약해지고…....

 

이때 이러한 문제를 해결할 수 있는 방법이 Refresh토큰이다!!

 

Refresh토큰은 JWT와 똑같은 형태이다.

 

처음 로그인을 했을때 Access토큰과 Access토큰 보다 유효시간이 비교적 긴 Refresh토큰을 발급해 줍니다.

이렇게 발급한 2가지 토큰은 매 요청마다 Access토큰은 Header에 담고, Refresh토큰은 cookie에 담아서 로직을 수행합니다.

나는 Refresh토큰을 Cookie에 담아서 요청을 보내는게 더 보안상 안전하다고 어디서 들은거같다.

 

그래서 한번 알아본 결과

쿠키는 JavaScript로 접근이 불가능하다. 그래서 localStorage만큼 XSS 공격에 취약하지 않다.

라는 내용으로 보안에 더 좋다는 것을 확인 할 수 있었다.

그러면 이제 어떤 흐름으로 토큰들이 돌아다니는지 그려볼 차례이다.

 

인증과정

힘들게 만들었습니다...

  1. 사용자가 로그인 요청을 합니다.
  2. 로그인 처리 후 Access토큰과 Refresh토큰을 발급 합니다.(Refresh토큰은 DB에 저장)
  3. 발급한 토큰을 Access토큰은 Body에 Refresh토큰은 Cookie에 담아서 응답처리를 합니다.
  4. 매번 요청을 할 때 Access토큰과 Refresh토큰을 각각 headerdhk cookie에 담아서 요청합니다. 
  5. Access토큰을 검증 하고 존재하지 않는 토큰이면 예외처리, Access토큰이 유효시간이 초과했으면 Access토큰이 만료에러(costom exception)처리를 합니다.
  6. 만료 신호 처리
  7. 클라이언트에서 Access토큰 발급 요청을 합니다.
  8. Refresh토큰을 검증 하고 존재하지 않거나 유효 시간 초과 시 다시 로그인 요청, Access토큰이 유효시간이 초과했으면 Access토큰이 만료에러(costom exception)처리를 합니다.
  9. 새로운 access토큰 발급

 

이러한 과정으로 토큰을 주고 있고, 결론적으로 이러한 JWT을 적용했을때 이점은

  • session과는 다르게 모든 서버에서 세션 내용을 공유한다.
  • 매 요청시마다 DB 조회를 안하고 토큰 자체만으로 사용자의 정보와 권한을 알 수 있기에 병목현상을 방지한다.

 

github:https://github.com/ingpyo/login (OAuth랑 같이 있어서 보기불편하실 수 도있어요용...)