JWT는 Json Web Token으로 말 그대로 웹 토큰을 의미한다.

Json format을 이용해 사용자에 대한 속성을 저장하는 Claim 기반의 웹 토큰이다.

JWT는 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달한다.

그래서 주로 회원 인증이나 정보 전달에 사용된다.

 

JWT의 구조

JWT는 header, payload, signature 이렇게 세가지 부분으로 이루어진다.

각 부분은 Base64Url로 인코딩되어 표현되고 '.' 으로 구분한다.

 

jwt.io

 

HEADER

header는 typ와 alg 두가지 정보로 구성되어 있다.

typ는 토큰의 타입을 지정하고 alg는 토큰의 알고리즘 방식을 지정하게 된다.

 

 

PAYLOAD

payload는 토큰에서 사용할 정보의 조각들인 클레임(Claim)이 담겨있다.

클레임은 등록된 클레임(Registered Claim), 공개 클레임(Public Claim), 비공개 클레임(Private Claim)으로 나눠지며

json형태로 다수의 정보를 넣을 수 있다.

 

등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로, 모두 선택적으로 작성이 가능하며 사용할 것을 권장한다.

  • iss : 토큰 발급자(issuer)
  • sub : 토큰 제목(subject)
  • aud : 토큰 대상자(audience)
  • exp : 토큰 만료 시간(expriation), NumericDate 형식으로 되어 있어야 한다.
  • nbf : 토큰 활성 날짜(not before), 이 날이 지나기 전의 토큰은 활성화가 되지 않는다.
  • iat : 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간을 알 수 있다.
  • jti : JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token)등에 사용한다.

공개 클레임은 사용자 정의 클레임으로 공개용 정보를 위해 사용되며 충돌 방지를 위해 URI 포맷을 이용한다.

 

비공개 클레임은 사용자 정의 클레임으로 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.

 

 

SIGNATURE

signature(서명)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.

signature는 토큰의 header, payload를 각각 Base64Url로 인코딩 하고 이를 이용해 header의 alg에서 정의한 알고리즘으로 암호화 한 뒤 다시 Base64Url로 인코딩해 생성한다.

 

 

Signature 암호화 방식

signature를 생성할 때 사용하는 암호화 방식으로는 보통 두가지를 사용한다고 한다.

hs256방식과 RSA 방식인데 이 중에 더 많이 사용하는 방법은 hs256 방식이라고 한다.

 

 

HS256 방식

hs256 알고리즘은 두가지 알고리즘을 합친것이다.

h는 HMAC 알고리즘을 의미하는데 HMAC은 SecretKey를 이용한 암호화 방식이다.

s256은 SHA256 알고리즘을 의미하는데 해시함수 암호화 방식이다.

이 두가지를 합쳐서 h(HMAC) + s256(SHA256) = hs256 알고리즘이라고 부른다.

 

이 hs256 알고리즘은 서버의 secretKey를 이용해 암호화를 하는 방식이다.

이 암호화를 사용할 경우 처리 과정은 아래와 같다.

  1. header와 payload를 각각 Base64Url로 인코딩한다.
  2. signature는 인코딩된 header + payload + secretKey를 hs256으로 암호화한다.
  3. hs256으로 암호화된 signature를 Base64Url로 다시 인코딩해준다.

서버가 토큰을 받게 되면 서버는 토큰의 header와 payload + 자신의 secretkey를 hs256으로 암호화한 뒤 그 값을 토큰의 signature값과 비교를 해 토큰을 검증하게 된다.

 

 

RSA 방식

RSA 알고리즘은 public key(공개키)와 private key(개인키)를 사용하는 방식이다.

공개키는 누구나 알고 있어도 상관없는 말 그대로 공개되어 있는 키이고,

개인키는 소유자만이 알고 비밀이에 갖고 있어야 하는 키다.

RSA 방식의 특징으로는 개인키로 암호화를 하면 공개키로 열어볼 수 있고 공개키로 암호화를 하면 개인키로 열어볼 수 있다.

개인키로 잠궈놓는 것은 소유자만이 할 수 있기 때문에 전자 서명에 많이 사용되고,

공개키로 잠궈놓는 것은 암호화를 의미한다.

 

JWT에서 RSA 방식으로 signature를 생성하게 되면 아래와 같이 처리하게 된다.

  1. header와 payload를 각각 Base64Url로 인코딩한다.
  2. signature는 인코딩된 header와 payload를 서버의 개인키로 암호화 한다.
  3. 개인키로 암호화한 signature를 Base64Url로 인코딩한다.

서버는 토큰을 받게 되면 자신의 공개키로 signature를 복호화 해 자신이 만든 토큰이라는 것을 확인한 뒤 처리하게 된다.

 

처음 이 내용을 들었을때는 개인키로 암호화를 하는 경우 누구나 가질 수 있는 공개키로 열어볼 수 있는데 왜 개인키로 암호화를 하지? 라는 생각을 했는데

조금만 더 생각해보면 RSA 방식에서의 signature는 header와 payload의 조합이다.

이 토큰을 탈취해서 signature를 복호화 한다는 것은 header와 payload의 값을 볼 수 있다는 것인데 그건 굳이 signature를 복호화 하지 않아도 확인할 수 있는 정보고 Base64Url로 인코딩되어 있기 때문에 값을 확인하기도 쉽다.

그래서 payload에 중요정보를 넣으면 안된다고 하는것이기 때문에 문제의 포인트가 되지 않는다.

 

그리고 개인키로 암호화를 해서 공개키로 열어야 서버가 암호화를 했다는 것이 인증되는 것이나 마찬가지이기 때문이다.

공개키로 암호화를 하면 누구나 암호화를 할 수 있게 되고 서버가 암호화를 했다는 인증이 되지 않기 때문이다.

그래서 개인키를 전자서명에 사용하는 것이다.

 

 

JWT의 단점

  1. JWT는 토큰 자체에 정보를 담고 있으므로 양날의 검이 될 수 있다. 편하게 정보에 접근할 수 있지만 탈취당했을 때 유출에 대한 위험도 있다.
  2. 토큰의 payload에 3종류의 클레임을 저장하기 때문에 정보가 많아질수록 토큰의 길이가 늘어나고 이는 네트워크에 부하를 줄 수 있다.
  3. payload는 암호화된 것이 아니라 Base64Url로 인코딩 된 것이기 때문에 탈취하면 쉽게 데이터를 볼 수 있다. 그래서 JWE로 암호화를 하거나 중요데이터를 넣지 않아야 한다.
  4. JWT는 상태를 저장하지 않기 때문에 임의로 삭제하는것이 불가능하므로 토큰 만료 시간을 꼭 정의해야 한다.
  5. 토큰은 클라이언트측에서 관리해야 하기 때문에, 토큰을 저장해야 한다.

 

 

Reference

'Web' 카테고리의 다른 글

JWT 2. JWT 구현  (0) 2022.12.01
CI/CD란?  (0) 2021.12.28
Jenkins github webhook 연동  (0) 2021.12.28
Jenkins로 Spring Boot 프로젝트 빌드&배포하기  (0) 2021.12.24

+ Recent posts