[ CS / Web ] JWT (JSON Web Token)

황승환·2022년 7월 29일
0

CS

목록 보기
56/60

JWT (JSON Web Token)

JWT는 JSON Web Token를 줄인 말로, 말 그대로 두 개체에서 JSON 객체를 사용하여 가볍고 자기수용적인 방식으로 정보를 안전성 있게 전달해주는 웹 토큰이다.

JWT 사용 이유

보안

  • 쿠키나 세션이 탈취당하여 발생할 수 있는 보안 문제를 막을 수 있음
  • JWT는 쿠키를 사용하지 않기 떄문에 CORS(Cross-Origin Resourse Sharing) 에러가 발생하지 않음

용량

  • JWT는 기존의 XML보다 덜 복잡하고 인코딩된 사이즈가 작음
  • HTTP와 HTML 환경에서 사용하기 좋음

사용성

  • 서버 확장시, 토큰 정보만 공유하면 새롭게 추가된 서버에서도 바로 사용할 수 있음 (확장성 좋음)
  • 토큰 기반의 다른 인증 시스템과 상호 호환이 가능
  • 토큰에 필요한 별도의 저장소 관리가 필요 없음 (서버에 저장 X)

구성 요소

JWT는 .을 구분자로 3가지의 문자열을 가진다.
aaaa.bbbbb.ccccc의 구조를 가지며, 앞에서부터 순서대로 header(헤더), payload(내용), signature(서명)을 의미한다.

Header (헤더)

{
  	"typ": "JWT"
  	"alg": "HS256"
}

헤더에는 두가지 정보가 들어간다. typ, alg라는 이름으로 들어가는데, typ는 토큰의 타입에 대한 내용으로 JWT는 "JWT"가 들어간다. alg는 해싱 알고리즘에 대한 내용으로 HMAC, SHA256, RSA가 사용되면 토큰을 검증할 때 사용되는 signature부분에서 사용된다.

Payload (정보)

payload에는 토큰에 담을 정보가 들어간다. 하나의 정보 조각을 클레임(claim)이라 하고, name: value의 한 쌍으로 들어간다. 많은 클레임을 담을 수 있지만, 너무 많은 클레임을 넣을 경우에는 토큰이 너무 길어질 수 있다.

하나의 정보 조각인 클레임은 registered claim, public claim, private claim 이렇게 3가지 종류로 나뉜다.

Registered claim (등록된 클레임)

등록된 클레임은 서비스에 이용하기 위한 클레임이 아닌, 토큰에 대한 정보를 담기 위한 클레임이다. 그렇기 때문에 이미 이름이 정해져있다. 등록된 클레임은 Optional하다.

  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰 만료시간 (expiration)
    • NumericDate형식으로 입력되어야 하고, 항상 현재 시간 이후 시간으로 설정되어야 함
  • nbf: 토큰의 활성 날짜 (Not before)
    • NumbericDate형식으로 입력되어야 하고, 이 날짜가 지나기 전까지는 토큰이 처리되지 않음
  • iat: 토큰이 발급된 시간 (issued at)
    • iat를 통해 토큰의 age를 판단할 수 있음
  • jti: JWT의 고유 식별자
    • 주로 중복적인 처리를 방지하기 위해 사용되고, 일회용 토큰에 사용하면 유용

Public claim (공개 클레임)

공개 클레임은 충돌이 방지된(collision-resistant) 이름을 가지고 있어야 한다. 이를 위해 클레임 이름을 URI 형식으로 짓는다.

{
	"https://xx0hn.com/jwt_claims/is_admin": true
}

Private claim (비공개 클레임)

등록된 클레임, 공개 클레임과 다른 클레임으로 주로 양 측(클라이언트 <-> 서버)간의 합의 하에 사용되는 클레임이다. 공개 클레임과 달리 충돌을 방지할 수 없기 때문에 클레임명이 중복되지 않도록 주의해야 한다.

Signature (서명)

서명은 Header의 인코딩 값과 Payload의 인코딩 값을 합치고, 이를 주어진 비밀키로 해쉬를 하여 생성한다. 이렇게 만들어진 해쉬를 base64형태로 나타낸다.

JWT 사용

JWT는 보통 로그인 기능에 흔하게 사용된다. Payload 부분에 사용자의 정보를 넣은 JWT를 생성하여 클라이언트에게 발급해주면(서버에 저장 X) 이를 통해 회원 서비스를 이용하게 된다.

이때 JWT의 exp를 짧게 주게 되면, 사용자는 자주 로그인을 시도해야 하기 때문에 불편함을 느낄 것이고, exp를 길게 주게 되면, 공격자로부터 토큰을 탈취 당하는 보안상의 위험이 있다. 이를 보완하기 위해 Refresh Token을 사용하게 되었다.

Refresh Token은 Access Token과 같은 JWT로, Access Token을 발급받기 위한 티켓이라고 생각할 수 있다. Access Token이 만료되었을 때 Refresh Token을 통해 새로운 Access Token을 발급받을 수 있다.

이와 같은 방법을 사용한다면, Access Token의 exp를 짧게 부여하여도, 이보다 exp가 긴 Refresh Token을 통해 자동으로 새로운 Access Token이 발급되어 사용자의 불편함을 줄여줄 수 있고, Access Token의 exp는 짧기 때문에 탈취되어 공격당할 위험도 적다. 물론 Refresh Token도 탈취 당할 가능성은 있기 때문에 적절한 exp 설정이 필요하다.

Access Token + Refresh Token 인증 과정

  • (A) Authorization Grant: Access Token을 발급 받기 위해 클라이언트가 사용하는 Resource owner의 권한을 보여주는 자격 증명. 이를 통해 Access Token 발급 요청.
  • (B) Access Token & Refresh Token: Access Token과 Refresh Token을 서버로부터 발급받음
  • (C) Access Token: 리소스 서버에 권한이 필요한 API를 요청할 때 Access Token을 HTTP 헤더에 넣어 요청 전송
  • (D) Protected Resource: 권한이 필요한 요청에 대한 응답을 클라이언트에게 반환
  • (E) Access Token: 리소스 서버에 권한이 필요한 API를 요청할 때 Access Token을 HTTP 헤더에 넣어 요청 전송
  • (F) Invalid Token Error: 만료되었거나 잘못된 Access Token을 받았을 때 Invalid Token Error 반환
  • (G) Refresh Token: 새로운 Access Token을 발급 받기 위해 서버로 전송
  • (H) Access Token & Optional Refresh Token: Access Token을 재발급하고, 만약 Refresh Token도 만료되었다면 새로운 Refresh Token을 반환

정리

  • JWT는 JSON Web Token의 약자로, JSON을 활용한 토큰임.
  • 쿠키나 세션에 저장하지 않기 때문에 보안에 좋고, 쿠키를 사용하지 않아 CORS 에러도 발생하지 않음
  • JWT는 서버에 저장하지 않기 때문에 따로 저장 공간을 관리할 필요가 없음
  • 인증 기반 시스템에 호환 가능
  • 서버 확장의 경우, 토큰 정보만 공유하면 JWT를 통해 바로 이용 가능
  • XML보다 인코딩 결과값의 크기가 작고 덜 복잡함
  • HTTP, HTML에 사용하기 좋음
  • .을 구분점으로 3개의 문자열로 구분 가능 (header.payload.signature)
  • header에는 토큰의 타입과 해싱 알고리즘 정보가 저장됨
  • payload에는 토큰의 정보가 저장됨.
  • payload는 3가지로 구분할 수 있음 (registered, public, private)
  • registered claim은 서비스에 대한 정보가 아닌 토큰에 대한 정보로, 토큰 발급자(iss), 토큰명(sub), 토큰 대상자(aud), 토큰 만료시간(exp) 등이 저장됨.
  • public claim은 공개된 클레임이기 때문에 URL형식의 이름을 가져 충돌을 방지함.
  • public claim은 양측(클라이언트 <-> 서버)간의 합의 하에 사용한 클레임으로 충돌 방지가 불가하기 때문에 주의해야함
  • signature에는 header의 인코딩 값과 payload의 인코딩 값을 합하여 비밀키를 통해 해쉬하고, 이를 base64로 나타냄
  • 로그인에 주로 사용되고, 토큰 탈취 공격을 방지하기 위해 JWT를 이용하여 Refresh Token과 Access Token을 발급하여 사용.
profile
꾸준함을 꿈꾸는 SW 전공 학부생의 개발 일기

0개의 댓글