SpringbootSecurity

SpringbootSecurity/JWT구조에 대한 이해

25G 2021. 9. 4. 18:25

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

저번 포스팅에선 RFC문서가 뭔지에 대해서 이해를 했으니 이제 JWT가 뭔지 자세히 알아보자.

 

 

JSON웹 토큰이란?(JWT)

 

JSON웹 토큰은 JSON객체로 안전하게 정보를 전송하기 위한 방식이다. 이 정보는 디지털 서명이 되어 있으므로 신뢰할 수 있다. JWT는 HMAC알고리즘 또는 RSA를 사용한다.

JWT를 암호화하여 당사자간에 비밀을 제공 할 수도 있지만 이 JWT의 핵심은 서명된 토큰에 중점을 둔 것이다. 즉 서명의 용도로 사용을 하는 것이다.

 

JSON웹 토큰의 구조

xxxxx가 header (해더)

yyyyy가 Payload(정보)

zzzzz가 Signature(서명)

 

header

해더부분에는 어떤 알고리즘을 사용해서 서명을 했는지에 대한 내용을 입력한다.

 

Base64 URI로 인코딩 됐다는 말은 암호화를 한 상태에서 복호화를 할 수 있다는 뜻이다.

즉 암호화를 하고나서 디코딩을 할 수 있다.

 

Payload(정보)

 

이 payload는 세 가지 클레임이 있는데

위 클레임에서 중요한 것은 이 payload부분에 뭘 넣는지가 중요한 것인데 이 비공개 클레임에 user정보를 넣어 볼 것이다.

페이로드 부분에는 위와 같은 정보들을 담을 수가 있다.

 

Signature(서명)

 

이 서명 부분에는 우리가 만들었던 해더와 정보 그리고 개인키를 HS256(HMAC SHA256)으로 암호화를 한다.

 

 

그럼 header에 들어갈 HS256방식과 RSA방식을 이해해보자!

 

 

JWT에 구조의 이해를 돕기 위한 예시

클라이언트가 서버에게 ID:ssar PW:1234로 로그인 시도

사용자가 다음과 같이 서버에 요청했다고 가정을 해보자 

 

HS256 방식

 

header -> HS256

Payload -> {username: ssar}

signature -> header + Payload + 서버만 알고 있는 키값(Secret) -> 이 세 값을 더한 정보를 HS256 방식으로 암호화를 한다(해쉬).

(해쉬는 복호화 할 수 없는 키값을 만드는 것)

이때 HMAC 암호화 방식이 뭐냐면 시크릿키를 포함한 암호화를 한다는 것이다.

이 암호화된 각각의 데이터를 Base64로 인코딩을 한다. 그리고 이 인코딩 된 데이터를 클라이언트에게 돌려준다.

그럼 클라이언트는 로그인 시도를 한 것이니 인증이 완료가 되면 JWT를 만드는 것이다. 이때 이상한 난수를 돌려주는데 이 정보를 웹브라우저에 로컬 스토리지 영역에 저장한다.

 

 

자 이렇게 클라이언트에게 JWT를 넘겨줬으니 재요청시 어떻게 요청한 클라이언트에 대한 검증을 하냐면

예를 들어 이 유저의 JWT데이터는 'abc52'라고 하고 인증 관련 요청시에 클라이언트가 서버에게 JWT를  같이 넘겨주는데 이때 서버는 이 JWT가 신뢰할 수 있는지 검증을 한다. 어떻게 검증을 하냐면

처음 암호화를 했을 때처럼

signature에 HS256으로 암호화된 정보가 있을 텐데 이때 서버가 header와 Payload와 서버만 알고 있는 키값을 다 합해서 HS256으로 암호화를 해보는 것이다. 그래서 암호화를 해봤더니 'abc52'라는 유저의 토큰과 똑같은 값이 나왔다면 어떤 유저가 요청했는지 알 수 있다.(똑같은 방식으로 암호화해서 이 값과 같은 암호화된 값이 있는지 비교해보는것)

그럼 유저가 어떠한 정보를 달라고 요청을 하면 Payload에 user의 정보가 있으니 DB에서 SELECT 해서 사용자가 원하는 정보를 알려주면 되는 것이다.(왜냐하면 Base64로 인코딩된 데이터는 디코딩이 가능하기 때문)

 

 

 

 

RSA방식

 

 

header -> HS256

Payload -> {username: ssar}

signature -> header + Payload ->합친 데이터 암호화

RSA방식으로 하면 signature를 할 때 서버만 알고 있는 키값(secret) 값이 필요 없다.

어떻게 하냐면

RSA는 기본적으로 공개키와 개인키가 있다.

 

그럼 signature를 만들 때 haeder와 Payload를 서버 자신의 개인키로 잠가버리는 것이다. 이렇게 만들어진 토큰을 돌려준다.

그럼 이 토큰을 클라이언트가 받을 것이고 똑같은 클라이언트가 다시 요청을 하면 위에서 말했듯이 검증을 하는데

검증을 할 때 공개키로 signature를 열어보기만 하면 된다. 

 

 

 

위 글을 읽고 JWT가 이해가 됐다면 왜 JWT가 세션의 고질적인 문제를 해결할 수 있는지 알 수 있다

클라이언트가 요청을 할때 세션을 사용해서 서버에 인증을 요청하는 것이 아니라 JWT토큰으로 요청하기 때문에 서버들은 JWT를 검증만 하면 된다. 그렇다는 말은 서버들이 secret(서버만 알고 있는 키값) 값만 알고 있으면 어떤 서버에 요청이 들어가도 검증을 할 수 있다는 말이다.

그럼 이 검증이 완료되면 Payload에 있는 해당 사용자의 정보를 활용하면 된다.

그리고 중요한 것은 이 JWT는 누구나 만들 수 있는 것이 아니라 서버만 만들수 있기 때문에 서버에게만 유효한 값이라는 것이다.

 

 

 

추가 설명

 

JWT는 위와 같이 생겼다. 각각 Base64로 암호화가 돼있는데 Base64로 암호화돼있는 데이터는 디코딩을 할 수 있다는 뜻이다. 

즉 JWT는 암호화에 목적이 있는 게 아닌 서명에 목적이 있다는 것이다. 무결성을 검증하기 위한 데이 터지 비밀성을 보장하기 위한 데이터는 아니라는 뜻