JWT (Json Web Token) 이란?

아현·2022년 6월 19일
0

Computer Science

목록 보기
32/55
post-custom-banner

참고

1. 배경


  • 세션을 사용하면서 단점으로 꼽히는 것은 요청을 진행할 때마다 세션 저장소에 세션 ID를 조회하는 작업을 통해서 DB 접근이라는 로직이 한번 더 수행된다는 점, 이런 과정에서 그럼 이제는 더 좋은 방법이 없을까 하고 등장한 것이 JWT입니다.



2. JWT 란?


JWT의 등장


  • JWT(Json Web Token)은 위와 같은 일련의 과정 속에서 나타난 하나의 인터넷 표준 인증 방식입니다. 말 그대로 인증에 필요한 정보들을 Token에 담아 암호화시켜 사용하는 토큰인 것이죠.

  • 따라서 사실 기본적인 인증을 진행하는 구조는 Cookie때와 크게 다르지는 않습니다. 다만, 강조되는 점은 JWT는 서명된 토큰이라는 점입니다.

    • 공개/개인 키를 쌍으로 사용하여 토큰에 서명할 경우 서명된 토큰은 개인 키를 보유한 서버가 이 서명된 토큰이 정상적인 토큰인지 인증할 수 있다는 이야기이죠.

    • 이러한 JWT의 구조 때문에 인증 정보를 담아 안전하게 인증을 시도하게끔 전달할 수 있는 것입니다.



JWT 구조


  • JWT는 각각의 구성요소가 점(.)으로 구분이 되어있으며 구성 요소는 다음과 같습니다.

    • Header

    • Payload

    • Signature

  • 아래처럼 각각의 구성 요소가 점(.)으로 구분되어있는 형태이죠.



3. JWT 살펴보기


1) Header


  • header에는 보통 토큰의 타입이나, 서명 생성에 어떤 알고리즘이 사용되었는지 저장합니다.

  • 지금 같은 경우에는 현재 토큰의 타입이 JWT이고, 앞서 이야기했던 개인키로 HS512 알고리즘이 적용되어 암호화가 되어있다고 확인할 수 있겠네요.



2) Payload


  • payload에는 보통 Claim이라는 사용자에 대한, 혹은 토큰에 대한 property를 key-value의 형태로 저장합니다.

    • Claim이라는 말 그대로 토큰에서 사용할 정보의 조각

    사실 어떤 Claim값을 넣는지는 개발자의 마음

  • 표준 스펙상 key의 이름은 3글자로 되어있습니다. JWT의 핵심 목표는 사용자에 대한, 토큰에 대한 표현을 압축하는 것이기 때문에 이를 정의한 것이라고 볼 수 있겠네요.

    1. iss (Issuer) : 토큰 발급자

    2. sub (Subject) : 토큰 제목 - 토큰에서 사용자에 대한 식별 값이 됨

    3. aud (Audience) : 토큰 대상자

    4. exp (Expiration Time) : 토큰 만료 시간

    5. nbf (Not Before) : 토큰 활성 날짜 (이 날짜 이전의 토큰은 활성화되지 않음을 보장)

    6. iat (Issued At) : 토큰 발급 시간

    7. jti (JWT Id) : JWT 토큰 식별자 (issuer가 여러 명일 때 이를 구분하기 위한 값)

이러한 표준 스펙으로 정의되어있는 Claim 스펙이 있다는 것이지, 꼭 이 7가지를 모두 포함해야 하는 것은 아니고, 상황에 따라 해당 서버가 가져야 할 인증 체계에 따라 사용하면 됩니다.

표준 스펙 외에도 필요하다 싶으면 추가해도 전혀 문제가 없습니다. 그건 개발자의 자유니 까요.

  • 예를 들어 뒤에서 이야기하겠지만 Access Token과 Refresh Token을 구분하고 싶다면 "token_type"라는 커스텀한 Claim을 만들고 값을 아래와 같이 "access token"으로 두어 구분 지어도 괜찮습니다.

  • 다만 가장 중요한 것은 payload에 민감한 정보를 담지 않는 것입니다.

    • 위에 header와 payload는 json이 디코딩되어있을 뿐이지 특별한 암호화가 걸려있는 것이 아니기 때문에 누구나 jwt를 가지고 디코딩을 한다면 header나 payload에 담긴 값을 알 수 있기 때문이죠.
  • 아래의 디코딩 과정을 보면, jwt.io에서 서버에서 생성한 JWT를 넣기만 해도 볼 수 있는 화면입니다.

    • JWT에서 header와 payload는 특별한 암호화 없이 흔히 사용할 수 있는 base64 인코딩을 사용하기 때문에 서버가 아니더라도 그 값들을 확인할 수 있습니다.

    • 그래서 JWT는 단순히 "식별을 하기 위한" 정보만을 담아두어야 하는 것입니다.


  • 간혹 JWT의 header나 payload가 식별 값만 존재하지만 해당 값들도 암호화를 통해 감추어야 하지 않느냐는 생각을 가졌을 때가 있습니다.

    • 예를 들어 base64UrlEncode(암호화(header)).base64UrlEncode(암호화(payload)).signature(암호화된 이 둘을 또 암호화)와 같은 형태였습니다.

    사실 필요 없는 행위입니다. 암호화는 민감한 정보를 막아두어야 할 때는 필요한 행위이지만 이 자체만으로도 많은 리소스를 사용하기 때문에 신중하게 사용해야 합니다.
    매 http 요청마다 한 번의 복호화가 더 추가되는 셈이니까요.

  • 그렇기 때문에 유출되었을 때 그렇게 큰 상관이 없는 비민감정보를 토큰에 담는 것이 기본 스펙이 되는 것이고, 서버는 굳이 header나 payload를 암호화하지 않아도 되는 것입니다.



3) Signature


  • 가장 중요한 서명입니다.

    • 암호화가 되어있기 때문에 그 구조에 대한 이미지
  • 지금까지 Header와 Payload를 보여줄 때는 인코딩 되어있던 값들을 JWT에 담겨있는 것처럼 디코딩된 상태를 사용합니다.

    • header를 디코딩한 값, payload를 디코딩한 값을 위처럼 합치고 이를 your-256-bit-secret 즉, 서버가 가지고 있는 개인키를 가지고 암호화되어있는 상태입니다.
  • 따라서 signature는 서버에 있는 개인키로만 암호화를 풀 수 있으므로 다른 클라이언트는 임의로 Signature를 복호화할 수 없습니다.

  • 잘 생각해보면 위에 설명한 내용만 봐도 어떻게 복호화해서 인증하는지는 알 수 있을 것입니다.

    1. JWT 토큰을 클라이언트가 서버로 요청과 동시에 전달한다.

    2. 서버가 가지고 있는 개인키를 가지고 Signature를 복호화한 다음 base64UrlEncode(header)가 JWT의 heaer값과 일치한 지, base64UrlEncode(payload) 와 일치한 지 확인하여 일치한다면 인증을 허용합니다.

  • 만약 클라이언트가 payload에 담긴 식별자가 변조된 JWT로 요청을 하더라도 서버가 애초에 발급했던 Signature 안의 payload와 다르기 때문에 인증이 불가능해지겠죠.



4. 장점


  • 지금까지 쿠키와 세션을 넘어오면서 겪었던 모든 단점을 해결하는 것이 JWT인 것이기 때문에 단점들을 뒤집으면 JWT의 장점이라고 볼 수 있을 것 같습니다.

  • 이미 토큰 자체가 인증된 정보이기 때문에 세션 저장소와 같은 별도의 인증 저장소가 "필수적"으로 필요하지 않습니다.

    • 세션과는 다르게 클라이언트의 상태를 서버가 저장해 두지 않아도 됩니다.

    • signature를 공통 키 개인키 암호화를 통해 막아두었기 때문에 데이터에 대한 보완성이 늘어납니다.

    • 다른 서비스에 이용할 수 있는 공통적인 스펙으로써 사용할 수 있습니다.



5. 요약


처음 글부터 지금까지의 내용을 한 문장으로 요약하자면

stateful 해야 하는 세션의 단점을 보완하기 위해 만들어진 JWT는 별도의 세션 저장소를 강제하지 않기 때문에 stateless 하여 확장성이 뛰어나고, signature를 통한 보안성까지 갖추고 있다.



profile
For the sake of someone who studies computer science
post-custom-banner

0개의 댓글