1. JWT(JSON Web Token) 이란?

  • JSON Web Token의 약자로 전자서명 된 URL-safe (URL로 이용할 수 있는 문자로만 구성된)의 JSON
  • 전자서명(Signature)은 JSON의 변조를 체크할 수 있게 되어 있다.
  • 속성 정보(Claims)를 JSON 데이터 구조로 표현한 토큰으로 RFC 7519 표준
  • 서버와 클라이언트 간 정보를 주고 받을 때 HttpRequest header에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정없이 헤더에 포함되어 있는 JWT 정보를 통해 인증한다.
    이때 사용되는 JSON 데이터는 URL-safe 하도록 URL에 포함할 수 있는 문자만으로 만든다.
  • HMAC 알고리즘을 사용하여 비밀키 또는 RSA를 이용한 Public Key / Private Key 쌍으로 서명할 수 있다.
Base64 인코딩의 경우 "+", "/", "="이 포함되지만 JWT는 URI에서 파라미터로 사용할 수 있도록 URL-Safe 한 Base64url 인코딩을 사용한다.

2. JWT 구조

  • Claims를 userId, username으로 하고, JWA 알고리즘 SHA-256으로 암호화
jwt:
  secret: 12345678901234567890123456789000
public String createToken(Long userId, String name) {
        return Jwts.builder()
                .setHeaderParam("typ", Header.JWT_TYPE)
                .signWith(key, SignatureAlgorithm.HS256)
                .claim("userId", userId)
                .claim("userName", name)
                .setExpiration(new Date(System.currentTimeMillis() + 864000000))
                .compact();
}
  • 위 작업을 통해 생성된 토큰 구성
// Header
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
// Payload
eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoic2VvayIsImV4cCI6MTU5MzUyMTU0MX0.
// signature
AWsWjhGSeAIr9d0LGdDuFbGK57iK_mdsEnxt983h_1o

[Header]

  • token의 type과 JWT를 digitally sign할 때 사용한 algorithm을 정의
  1. typ
  • 토큰의 타입을 지정 ("JWT")
  1. alg
  • 해싱 알고리즘을 지정한다.
  • 해싱 알고리즘으로는 보통 HMAC SHA256 혹은 RSA가 사용되며, 이 알고리즘은 토큰을 검증할 때 사용되는 signature 부분에서 사용된다.
{
    "typ" : "JWT",
    "alg" : "HS256"
}
  • 위 내용을 Base64url 인코딩 한 결과
// Header
eyJhbGciOiJIUzI1NiJ9.

[Payload]

  • JWT에 담아서 전달할 data를 정의

  • 정보의 한 "조각"을 Claim이라 부르고, name / value의 한 쌍으로 이루어져있다.

  • Claim의 종류

    • Registered Claim

      • 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기 위하여 이름이 이미 정해진 Claim

      • 모두 선택적(optional) 이다.

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

      • 충돌이 방지된(collision-registant)이름을 가지고 있어야 한다.
      • 충돌을 방지하기 위하여 Claim 이름을 URI 형식으로 짓는다.
    • Private Claim

      • 서버 클라이언트 양측 간 협의하에 사용되는 Claim이름
      • Public Claim과는 달리 이름이 중복될 수 있으니 사용시 유의
public String createToken(Long userId, String name) {
        return Jwts.builder()
                .setHeaderParam("typ", Header.JWT_TYPE)
                .signWith(key, SignatureAlgorithm.HS256)
                .claim("userId", userId)
                .claim("userName", name)
                .setExpiration(new Date(System.currentTimeMillis() + 864000000))
                .compact();
}
  • 위 내용을 암호화한 Payload
// Payload
eyJ1c2VySWQiOjEwMDQsInVzZXJOYW1lIjoiSm9obiJ9.

[Signature]

  • JSON Web Token의 마지막 부분으로 HeaderPayload를 base64로 encode인코딩한 값을 합친 후 JWT secret key값을 encrypt한 값으로 Hash를 하여 생성
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  my-secret-key

) secret base64 encoded
  • 위 내용으로 인코딩한 결과 값
// signature
0nwaeM3fpDPvRGc64pyIp-JYNnuigCN9t_5ApVhPClQ

JWT Token 예시

  • 생성된 토큰은 HTTP 통신을 할 때 Authorization이라는 key의 value로 사용된다.
  • 일반적으로 value에 Beare이 앞에 붙여진다.
{
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoic2VvayIsImV4cCI6MTU5MzUyMTU0MX0.AWsWjhGSeAIr9d0LGdDuFbGK57iK_mdsEnxt983h_1o"
}

JWT Decoding

3. JWT를 사용하는 상황

  • 회원 인증
    1. 사용자가 로그인을 하면, 서버는 사용자의 정보를 기반으로한 토큰을 발급
    2. 그 후, 사용자가 서버에 요청을 할 때마다 JWT를 포함하여 전달
    3. 서버는 클라이언트에서 요청을 받을 때 마다, 해당 토큰이 유효하고 인증되었는지 검증을 하고, 사용자가 요청한 작업에 권한이 있는지 확인하여 작업을 처리
    4. 서버에서는 사용자에 대한 세션을 유지할 필요가 없다.
      즉, 사용자가 로그인되어 있는지 여부를 신경 쓸 필요가 없고, 사용자가 요청을 했을 때 토큰만 확인하면 되므로 세션 관리가 필요 없어서 서버 자원과 비용을 절감할 수 있다.
  • 정보 교류
    • JWT는 두 개체 사이에서 안정정있게 정보를 교환하기에 좋은 방법
    • 정보가 서명이 되어있기 때문에 정보를 보낸이가 바뀌진 않았는지, 또 정보가 도중에 조작되지 않았는지 검증을 할 수 있다.
* UI Layer, REST API 서버를 따로 두는 경우 JWT를 사용
* 하나의 End Point가 아닌 Mobile / Web 등의 multiple EndPoint 환경이라면 통합적인 인증 / 인가 환경을 제공하기 위해 JWT를 사용
* Third Party에게 public하게 open 한 REST EndPoing가 존재하는 경우 해당 Third Party의 인증 인가를 관리하기 위해 JWT 사용

+ Recent posts