JWT

JWT(Json Web Token)은 당사자 간에 정보를 JSON 객체로 안전하게(securely) 전송하기 위한 표준이다.

JWT를 이용하여 암호화 된 정보를 전송하는 용도로 사용할 수도 있지만 서명된 토큰(Signed tokens)으로써 활용이 가능하다.

토큰에 서명을 하며 데이터를 전송하며 데이터의 무결성을 보장할 수 있다.

JWT의 사용은 크게 2가지로 나뉜다.

  • Authorization

  • 정보 교환

JavaScript에서 JWT 만들기

  1. jsonwebtoken 패키지 설치

    npm i jsonwebtoken
    
  2. JavaScript로 토큰 encoding, decoding

    const jwt = require("jsonwebtoken");
    const SECRET = "ThisIsSecretKey";
    const token = jwt.sign(
      {
        nickname: "EarlyHail",
      },
      SECRET,
      {
        expiresIn: "1h",
      }
    );
    console.log(token);
    // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNrbmFtZSI6IkVhcmx5SGFpbCIsImlhdCI6MTYxMjUxNDQ2OCwiZXhwIjoxNjEyNTE4MDY4fQ.gbWjnO0lES0IZF4kHFri0wc5DjG2oukE-cjBPcfuEj64
    const decodedToken = jwt.verify(token, SECRET);
    console.log(decodedToken);
    // { nickname: 'EarlyHail', iat: 1612514473, exp: 1612518073 }
    

Signed JWT의 구조

JWT의 구조를 알아보자.

위에서 만들어본 JWT를 자세히 보면 .를 이용하여 총 3 부분으로 나뉘어 있는것을 확인할 수 있다.

  1. Header

    헤더는 일반적으로 두 부분으로 나뉘며, 토큰 유형 (JWT)와 Signature Algorithm의 정보가 들어가있다.

    위 정보를 Base64Url로 인코딩한 정보를 삽입한다.

  2. Payload

    토큰화한 데이터가 들어가있다. 만들어진 시간, 만료 시간 등의 데이터가 추가로 들어갈 수 있다.

    위 정보를 Base64Url로 인코딩한 정보를 삽입한다.

  3. Signature

    Header와 Payload를 각각 base64Url로 인코딩 한 값과 SECRET을 함께 서명 알고리즘을 적용한 결과값이 들어가있다.

JWT 홈페이지에서 Encoding, Decoding을 테스트해볼 수 있다.

JWT-encoding-decoding-example

민감한 정보를 JWT에 넣으면 안된다!!!

Signed token은 데이터 변조로부터 보호되는 무결성을 보장하지만 기밀성을 보장하지 못한다.

token1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJuaWNrbmFtZSI6IkVhcmx5SGFpbCIsImlhdCI6MTYxMjUxOTk2MywiZXhwIjoxNjEyNTIzNTYzfQ.
akFIGyO0JUbJ2oJU3n2eM4UBku0Bk6mGsOJijpWDzEY

token2
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJuaWNrbmFtZSI6IkVhcmx5SGFpbCIsImlhdCI6MTYxMjUxOTk2MywiZXhwIjoxNjEyNTIzNTYzfQ.
sWJ2g0503AnN1pe8mGQT_BAqlXdfYFmxCo56fyuB4mg

두 개의 토큰은 서로 다른 SECRET으로 만들어진 토큰이다.

SECRET이 다르기 때문에 Signature를 제외한 Header, Payload의 값이 같은 것을 확인할 수 있다.

위 두 값은 Base64Url로 인코딩 되어있기 때문에 간단하게 해독할 수 있다. 따라서 기본 JWT 토큰에 저장되는 값 자체는 어떠한 보안적 처리도 되지 않은 상태이다.

위 이유 때문에 토큰을 브라우저의 localStorage나 cookie에 저장하는 것을 지양해야 한다.

JWT가 탈취되면 어떤 상황이 일어날까

JWT가 탈취되면 어떤 상황이 일어날 수 있을지 생각해보자.

  1. JWT에 담겨져 있는 데이터를 확인할 수 있다.

    JWT의 Payload값을 알아낼 수 있다.

    만약 JWT가 비밀번호 같은 민감한 정보를 포함한다면 큰 문제가 될 수 있다.

  2. JWT 탈취자는 사용자 행세를 할 수 있다.

    JWT를 이용하여 인증을 하는 서버의 토큰을 탈취한 사람은 해당 사용자인 것 처럼 권한을 가지고 접근할 수 있을 것이다.

    따라서 토큰 자체를 숨겨야 하는건 당연하고 토큰의 유효기간을 짧게 설정하는 방법도 적용을 고려해보는게 좋을것 같다.

이 외에 생각해본 문제가 있다.

  • Payload를 Decode해서 사용자의 이름을 변경하고 제 3자의 권한을 가지고 서버에 접근할 수 있을까?

    Payload에 “A” 유저 ID가 있을 때, 이를 “B” 유저 정보로 바꿔서 접근할 수 있을까?

    답은 안된다이다. Header와 Payload의 값을 서명 알고리즘인 HMAC(keyed-hash message authentication code, hash-based message authentication code)을 통해 Signature를 생성한다.

    인증을 위해 보내진 토큰의 Header, Payload는 무결섬 검증을 위해 복호화된 Signature 내의 Header, Payload와 비교되어 변경이 있다면 인증이 불가능하다.


Reference

JWT introduction