[Spring] jwt란 - jwt 내부구조, 동작과정, 스프링에서 파싱하기
같이 보면 좋을 연결된 포스팅들
- ✔️ Spring Jwt Refresh Token - 인증 인가의 흐름
- 👉 [Spring] jwt란 - jwt 내부구조, 동작과정, 스프링에서 파싱하기
- ✔️ [Spring] Spring JWT 인코딩, 디코딩 하기 - Java Json 파싱
이전 포스팅에서 인증과 인가의 흐름, 인증하는 방법들에 대해 공부를 해보았고
이번에는 실질적으로 자주 사용하고 사용되는 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가지를 담고 있습니다.
- typ : 토큰의 타입을 지정합니다. 바로 JWT 입니다.
- alg : 해싱 알고리즘을 지정합니다. 해싱 알고리즘으로는 보통 HMAC SHA256 혹은 RSA 가 사용되며, 이 알고리즘은, 토큰을 검증 할 때 사용되는 signature 부분에서 사용됩니다.
- 헤더는 토큰 타입과, 해시 암호화 알고리즘 정보 2가지를 담고 있습니다.
- Payload
- 페이로드는 토큰의 정보를 담는 부분입니다.
- 토큰에 담기는 정보의 한 조각을 "클레임(claim)"이라 하며 name : value 로 이루어져있습니다.
- 클래임의 종류는 크게 3가지 입니다. (등록된 클레임, 공개 클레임, 비공개 클레임)
- Signature
- 시그니처는 토큰의 정보가 신뢰할 수 있는 것인지 판단할 수 있도록 합니다.
- 시크릿 키를 포함하여 암호화 되어있습니다.
📌 Payload 클레임의 종류
1) 등록된 클레임 (Registered Claim)
- 토큰에 대한 정보를 담기위해 이름이 이미 정해진 클레임들 입니다. 클레임의 사용은 모두 선택적(Optional) 입니다.
- iss : 토큰 발급자 (issuer)
- sub : 토큰 제목 (subject)
- aud : 토큰 대상자 (audience)
- exp : 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
- nbf : Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
- iat : 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
- 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 발급 과정
- 사용자 정보를 바탕으로 인증이 되면, 시크릿 키를 활용해서 JWT 를 발급합니다.
JWT 유효성 검사 과정
- 사용자가 요청에 JWT 를 보내면 서버에서 시크릿키 만을 이용해서 JWT의 토큰의 유효성을 체크합니다. (Signature)
- 유효한 토큰이라면 사용자 인증을 거칩니다. (Payload)
- 그 다음, 토큰의 만료기간을 체크하고
- 권한을 체크합니다.
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
*참고
- jwt token : https://bbbicb.tistory.com/48
- jwt payload : https://velopert.com/2389