본문 바로가기

Web/Concept

[Web] JWT(JSON Web Token)

다시 정리하는 !!!!! 

 

 💡 Web의 인증 방식 중 세션의 메모리 문제를 보완할 수 있는 JWT에 대해 알아보자!

     노션에서 보기

 


📌 요약

  • JWT란, 인증에 필요한 정보들을 암호시킨 토큰으로 세션 기반 인증 방식의 문제점을 보완하는 기술이다.

세션의 단점

  • 세션 기반의 인증 방식을 사용할 때, 중앙 세션 관리 시스템에서 하나의 문제가 시스템 전체로 확산된다는 문제점 존재

 

  • 사용자가 많아짐에 따라 세션 DB와 서버 확장 필요
    • 예를 들어, 내가 사용중인 웹사이트의 사용자가 많아져 세션 DB를 A와 B로 나우었다고 가정하면,
    • 나에 대한 정보는 세션 A에 저장되어 있었다.
    • 따라서 앞으로 해당 웹 페이지에 Request를 보낼 때 세션 A에서만 통신하도록 하는 추가적인 기술이 필요하다.

 

→ 이러한 단점을 어느 정도 해결할 수 있는 기술이 JWT인 것

 


JWT란?

🔐 JWT(JSON Web Token)의 개념

  • JWT(JSON Web Token)란, 인증에 필요한 정보들을 암호시킨 토큰이다.
    • 토큰의 기본 정보, 전달할 정보, 검증되었다는 Signature 정보를 가지고 있다.
    • 필요한 모든 정보를 자체적으로 지니고 있다는 점에서, 자기 수용적(Self-Contained) 특징을 가지고 있다.
  • JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT 토큰(Access Token)을 HTTP 헤더에 실어 → 서버가 클라이언트를 식별하도록 한다.

 

JWT 사용

 

 

  • 로그인
    1. 클라이언트가 ID + Password로 로그인을 요청
    2. 서버가 ID + Password 일치 여부를 확인하고, 유효할 경우 토큰(JWT)를 발급
    3. 클라이언트가 다음에 어떤 요청을 할 때, 발급받은 인증 토큰을 헤더에 포함시켜 요청
    4. 서버에 요청이 오면, 헤더에 포함된 인증 토큰을 해석해 권한 확인
  • 정보교류
    • 두 개체 사이에서 안정성 있는 정보 교환 가능
    • 정보가 내장되어 있어, 정보를 보낸 이가 바꾸거나 조작하지 않았는지에 대한 사실 검증 가능

 

🔗 JWT의 구조

  • JWT는 Header(헤더) . Payload(페이로드) . Signature(서명) 세 부분을 ‘ . ‘ (구분자)으로 구분한다.
     💡 aaaa . bbbb . cccc
           헤더    내용     서명

 

  1. Header
  • [alg]와 [typ]의 두 가지 정보로 구성
    • alg : Signature를 해싱하기 위한 알고리즘 지정
      • 토큰 검증 시 사용되는 Signature 부분에서 사용
      • Ex) HS256(SHA256) or RSA
    • typ : 토큰의 타입 지정
      • Ex) JWT
{ 
 "alg": "HS256",
 "typ": JWT
}

 

    2. Payload

  • 토큰에 담을 정보를 지님
    • 클라이언트의 고유 ID 값, 유효기간 등이 포함되어 있음
    • key-value 형식으로 이루어진 한 쌍의 정보를 Claim(클레임) 이라고 칭함
    • 토큰에는 여러 개의 클레임을 넣을 수 있다.
    { 
    	"sub": "123456789",
      "name": "Mi Gyeong",
      "lat": 1516239022
    }
    

 

  • 클레임의 종류
    • 등록된(Registered) 클레임
      • 토큰의 정보를 표현하기 위해 이미 정해진 종류의 데이터
      • 서비스에 필요한 정보가 아닌, ‘토큰에 대한 정보'를 담기 위한 클레임이다.
      • 선택적으로 작성 가능하다.
      • Key의 String 길이는 3이다.
      • subject는 유니크한 값으로, 사용자 이메일을 사용한다.

    Key Value
    iss(issuer) 토큰 발급자
    sub(subject) 토큰 제목
    aud(audience) 토큰 대상자
    exp(expiration) 토큰 만료 시간 - 항상 현재 시간 이후로 설정 -> NumericDate 형식Ex) 1480849147370
    nbf(not before) 토큰 활성 날짜 - 해당 날짜 전의 토큰은 비활성화 상태
    iat(issued at) 토큰 발급 시간 - 토큰 발급 이후 경과 시간(토큰의 age)
    jti(JWT ID) JWT 토큰 식별자 - 중복 방지 및 일회용 토큰(Access Token) 등에 사용
    • 공개(Public) 클레임
      • 사용자 정의 클레임
      • 공개용 정보를 위해 사용
      • 충돌 방지를 위한 이름으로 URI 포멧 사용
      { 
      	"<https://simmigyeong.tistory.com/>": true 
      }
      
        
    • 비공개(Private) 클레임
      • 사용자 정의 클레임
      • 서버와 클라이언트 사이에 임의로 지정한(필요한) 정보를 저장
      • 공개 클레임과 달리, 중복 시 충돌 가능성이 있어 사용 시 유의해야 함
      { 
      	"username": "migyeong" 
      }
      
       

   3. Signature

 

  • Signature는 인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성한 암호화 코드이다.

 

  • Header와 Payload는 단순히 인코딩된 값이므로, 제 3자가 복호화 및 조작할 수 있지만, 
    • 서명에 사용되는 비밀키는 외부에 노출되지 않도록 주의해야 한다!!
    • 비밀키가 외부에 노출되는 경우, 누구나 서버 인증을 통과하는 Signature를 만들 수 있으므로, 인가되지 않은 요청들이 통과될 수 있다.
  • Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상, 복호화할 수 없다.

 

  • Signature는 토큰의 위변조 여부를 확인하는 데 사용된다.

 

  • Signature 생성 과정
    1. Header(헤더)와 Payload(페이로드)의 값을 각각 BASE64로 인코딩하고,
    2. 인코딩한 값을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱을 하고
    3. 이 값을 다시 BASE64로 인코딩하여 생성한다.

 

HEADER  PAYLOAD  VERIFY SIGNATURE
{  "alg": "HS256",  "typ": "JWT"} {  "sub": "1234567890",  "name": "Sim",  "iat": 1516239022} HMACSHA256(   
base64UrlEncode(header) + " . " +    base64UrlEncode(payload)
) 한 값을 Base64 인코딩

 

  • 헤더와 페이로드, 서명에 해당하는 내용이 각각 인코딩되어 JWT로 나타나는 결과값은 아래와 같다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNpbSIsImlhdCI6MTUxNjIzOTAyMn0.1MjAckWhJVC91zNAL9lfbT0TU-5eUNKUKFujNLABmPA

 


❗️ Access Token & Refresh Token

⏱ 토큰의 만료 시간

  • 토큰을 한 번 발행하고 → 클라이언트에 보내고 나면, 이후 서버에서는 토큰을 파괴시킬 방법이 존재하지 않는다.
  • 보통 JWT 토큰은 클라이언트 로컬 Storage에 저장하고 사용하게 되는데, 이때 토큰의 탈취 현상이 일어난다면?
  • → 해당 토큰을 서버에서 제어할 수 없는 문제가 발생한다.
💡 따라서, 토큰을 발행할 때는 만료시간을 필수로 넣어주어야 한다.

 

  • 그렇다면, 토큰의 만료 시간을 무조건 짧게 해야할까?
    • 물론, 보안을 위해서라면 만료 시간을 짧게 설정하는 것이 맞는 방법 같지만,
    • 막연하게 짧게 설정할 경우, 토큰이 만료될 때마다 사용자는 다시 로그인을 하거나/서버는 매번 토큰을 새로 발행해야 한다.
  • 그렇다고, 토큰의 만료시간을 무제한으로 늘려야 할까?
    • 사용자의 편리함과 서버의 부하를 줄이기 위해서라면, 토큰의 만료시간을 무조건 늘리는 게 좋을 것이지만,
    • 보안에 취약하다는 치명적인 문제가 발생한다.
  • 이러한 토큰의 만료시간 문제를 적당히 보완하고, 중간 지점을 맞추기 위해 등장한 것이 Access Token 과 Refresh Token 이다!

 

🗝 Access Token

  • 리소스에 직접 접근할 수 있도록 해주는 정보만을 가지고 있다.
  • Refresh Token에 비해 짧은 만료 시간을 가진다.

 

🗝 Refresh Token

  • 새로운 Accss Token을 발급받기 위한 정보를 가지고 있다.
  • 클라이언트가 Access Token이 없거나 만료될 경우 → Refresh Token을 통해 서버에 요청해서 새로운 Access Token 을 발급받을 수 있다.
  • Access Token에 비해 긴 만료 시간을 갖는다.
  • 외부에 노출되지 않도록 관리하기 위해 DB에 저장한다.

🔑 JWT의 인증 과정

 

 

   1. Autorization Grant

  • 사용자가 ID와 Password를 통해 로그인 요청을 보내 권한을 요청한다.

 

   2. Access Token 발급

  • 로그인이 정상적으로 완료되면(인증에 성공할 경우) JWT, Access Token, Refresh Token 을 발급한다.

 

   3. Access Token을 이용해 API를 요청

  • 클라이언트가 Resource Server(특정 서비스를 제공하는 서버)에 접근을 요청할 때, 발급받은 토큰을 Request Header를 통해 Resource Server 에 보낸다.

 

   4. Protected Resource 응답

  • Resource Server가 Access Token을 받아 검증한다.
  • Access Token에 문제가 없다면 요청에 정상적으로 응답한다.

 

   5. Access Token이 만료되면

 

 

   6. Access Token 재발급 요청

  • 클라이언트가 토큰 만료 신호를 받게 되면, 토큰을 재발급 받는 API로 Refresh Token을 보내 재발급을 요청한다.

 

   7. Access Token 재발급

  • Reresh Token이 정상적인 토큰인지 확인한 후 Access Token 을 발급한다.

 


⭕️ JWT의 장점

  • Hader와 Payload를 통해 Signature를 생성하므로, 데이터 위변조를 방지할 수 있다.
  • 인증 정보에 대한 별도의 저장소가 필요없다.
  • JWT는 토큰의 기본정보, 전달할 정도, 토큰의 검증을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.(Self-Contained)
  • 트래픽(서버와 스위치 등 네트워크 장치에서 일정 시간 내에 흐르는 데이터의 양)에 대한 부담이 낮다.
  • 클라의언트의 인증 정보를 저장하는 세션과 다르게, 서버는 Stateless 상태이다.
  • 확장성(로그인 정보가 사용되는 분야의 확장성)이 우수하다.
  • 토큰 기반으로, 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.
  • OAuth의 경우 소셜 계정을 이용해 다른 웹서비스에서도 로그인이 가능하다.
  • 모바일 어플리케이션 환경에서도 잘 동작한다.
  • REST 서비스로 제공 가능하다.

 

❌ JWT의 단점

  • 쿠키/세션과 달리 JWT는 토큰의 길이가 길어 → 인증 요청이 많아질수록 네트워크 부하가 심해진다.
    • 모든 요청에 대해 토큰을 전송하면 → 토큰에 담기는 정보가 많아지고 → 네트워크 부하가 증가할 것
  • 토큰을 탈취당할 경우, 대처하기 어렵다.
    • 따라서, Payload에 중요한 정보를 담아서는 안 된다.
  • 토큰은 발급 이후 유효기간이 만료될 때까지 계속해서 사용이 가능하므로, 즉 임의로 삭제가 불가능하므로 만료 시간을 필수로 지정해야 한다.

🔍 JWT와 Cookie/Session 의 차이

 

  장점  단점
Cookie & Session  1. Cookie 만 사용하는 방식보다 보안성이 향상
 2. 서버 쪽에서 Session의 통제 가능
 3. 네트워크 부하 낮음
 세션 저장소 사용으로 인한 서버 부하
JWT  1. 인증을 위한 별도의 저장소가 필요 없고
 2. 별도의 I/O 작업 없이 빠른 인증 처리 가능
 3. 확장성 우수
 1. 토큰의 길이가 늘어날수록 네트워크 부하
 2. 특정 토큰을 강제 만료시키기 어려움

🔖 참고 자료