Spring/Spring Boot

[Spring] jwt란 - jwt 내부구조, 동작과정, 스프링에서 파싱하기

민돌v 2022. 8. 18. 00:50
같이 보면 좋을 연결된 포스팅들

 

이전 포스팅에서 인증과 인가의 흐름, 인증하는 방법들에 대해 공부를 해보았고

이번에는 실질적으로 자주 사용하고 사용되는 JWT 토큰에 대해서 조금 더 자세하게 공부해 보고자 합니다.

 


 

JWT란

👏🏻 JWT는 Json Web Token의 약자로, 단어 그대로 Json 기반의 Web Token입니다.

 

발급된 토큰값을 Json 객체로 변환시켜 client에게 전송해주는 것을 말합니다.

JWT는 JWS(Json Web Signature) 와 JWE(Json Web Encryption)로 서명과 암호화 한 것 입니다.

 


 

JWT 구조

JWT가 발행되면, 발급된 jwt의 구성은 Header.Payload.Signature 3가지로 구성되며 . (점) 으로 구분됩니다.

  • header
    • 헤더는 토큰 타입과, 해시 암호화 알고리즘 정보 2가지를 담고 있습니다.
      1. typ : 토큰의 타입을 지정합니다. 바로 JWT 입니다.
      2. alg : 해싱 알고리즘을 지정합니다.  해싱 알고리즘으로는 보통 HMAC SHA256 혹은 RSA 가 사용되며, 이 알고리즘은, 토큰을 검증 할 때 사용되는 signature 부분에서 사용됩니다.
  • Payload
    • 페이로드는 토큰의 정보를 담는 부분입니다.
    • 토큰에 담기는 정보의 한 조각을  "클레임(claim)"이라 하며 name : value 로 이루어져있습니다.
    • 클래임의 종류는 크게 3가지 입니다. (등록된 클레임, 공개 클레임, 비공개 클레임) 
  • Signature
    • 시그니처는 토큰의 정보가 신뢰할 수 있는 것인지 판단할 수 있도록 합니다.
    • 시크릿 키를 포함하여 암호화 되어있습니다.

 


📌 Payload  클레임의 종류

1) 등록된 클레임 (Registered Claim) 

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

 

2) 공개 클레임 (Pulbic Claim)

  • 공개 클레임은 사용자 정의 클레임으로. 공개용 정보 전달을 위해 사용됩니다.
  • 충돌 방지를 위해 URI 포맷을 이용해야 합니다.
{
    "https://velopert.com/jwt_claims/is_admin": true
}

 

3) 비공개 클레임 (Private Claim)

  • 등록된 클레임도 아니고 공개된 클레임도 아닙니다. 서버와 클라이언트 양측간의 합의하에 정의된, 사용자 정의 클레임입니다.
  • 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할 때 조심해야한다고 합니다.
{
    "username": "velopert"
}

 

#) Payload 예제

{
    "iss": "tandohak.co.kr", // 등록된 클레임
    "exp": "1485270000000", // 등록된 클레임
    "https://tandohak.co.kr/is_authenticated": true, // 공개 클레임
    "username": "tandohak" // 비공개 클레임
}

 


 

 

사진은 jwt.io 에 실제 서버에서 발급받은 jwt 를 살짝 수정한 내용입니다.

위처럼, 페이로드에 데이터의 본문 내용을 담아 한 문장의 json으로 보낼 수 있는, 보시는거와 같이 매우매우 쉽게 인코딩하고 디코딩할 수 있습니다.

💡 그렇기 때문에 jwt (Payload) 에 유저 비밀번호와 같은 주요한 정보를 담으면 안됩니다.

 

 

 

jwt가 이렇게 쉽게 디코딩 되는 이유는 무엇이고?

그렇다면 어떻게 사용자를 식별할 수 있는걸까요??

 


 

 

JWT 사용자 식별 방법

 

jwt 헤더와 페이로드는 base64UrlEnCode(header) + "." + base64UrlEnCode (payload)로 암호화 되기 때문에

위와같이 웹 사이트에서도 쉽게 그 내용을 확인할 수 있습니다.. (그렇기 때문에 주요한 정보를 넣어서는 안되는 것입니다.)

 

 

👏🏻 하지만 Signature 이 header 와 payload가 base64로 인코딩 된 값을, 서버가 알고있는 시크릿 키로 다시 인코딩한 값입니다.

즉, 시크릿 키를 아는 서버만이 이를 디코딩할 수 있고 이 "고유한 값(Signature)" 으로 사용자를 식별할 수 있는 것입니다.

 


 

JWT 사용하는 이유는 무엇인가요?

 

점점 msa 기반으로 서비스가 확장되면서, 서버가 늘어나고 있는 추세입니다.

그런만큼, 인증에 대한 요청도 단순한 모놀리스식 1서버 방식보다 ➡️ MSA(가 아니더라도 로드밸런싱 등등) 의 N 개의 서버로 가면서  요청이 기하급수적으로 늘어날 수 있습니다.

 

💡 Jwt는 단순 문자열이기도 하며, 자체적으로 필요한 정보를 모두 담을 수있는 값 토큰(By Value Token) 이기 때문에 통신비용이 훨씬 적어 서버에 부담을 줄일 수 있다고 합니다.

 

 


 

Spring 에서 JWT 동작 과정

 

JWT 발급 과정

  1. 사용자 정보를 바탕으로 인증이 되면, 시크릿 키를 활용해서 JWT 를 발급합니다.

 

JWT 유효성 검사 과정

  1. 사용자가 요청에 JWT 를 보내면 서버에서 시크릿키 만을 이용해서 JWT의 토큰의 유효성을 체크합니다. (Signature)
  2. 유효한 토큰이라면 사용자 인증을 거칩니다. (Payload)
  3. 그 다음, 토큰의 만료기간을 체크하고 
  4. 권한을 체크합니다.

 

 


 

Spring 에서 JWT Payload 내용 확인하기

Spring Boot Jwt get Payload

payload 부분만 따로 때서 base64로 디코딩하는 방법을 사용했습니다.

@Test
void jwts_test() {
    String payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";
    Base64.Decoder decoder = Base64.getUrlDecoder();

    System.out.println(new String(decoder.decode(payload)));
}

 

 

 

더  자세한 내용 ⬇️

https://thalals.tistory.com/354

 

[Spring] Spring JWT 인코딩, 디코딩 하기 - Java Json 파싱

spring 에서 jwt 를 만들고, 외부에서 받아온 jwt 를 해석하는 방법과 jwt 해석한 byte 정보를 json 으로 파싱해서 jwt payload 에서 원하는 정보를 추출하는 방법 입니다. 📗 Spring JWT 만들기 Token 을 만드는

thalals.tistory.com

 

 


*참고