JWT(JSON Web Token)

이건·2025년 3월 26일

JSON 웹 토큰

JWT(JSON Web Token)는 클레임 토큰 기반의 인증 방식으로, 사용자 인증 및 정보 전달에 사용되는 안전한 방법이다.

JWT는 당사자 간의 비밀을 제공하기 위해 암호화될 수 있지만, 서명된 토큰에 초점을 맞춘다 . 서명된 토큰은 그 안에 포함된 클레임의 무결성을 확인할 수 있는 반면, 암호화된 토큰은 다른 당사자에게 해당 클레임을 숨긴다 . 토큰이 공개/비공개 키 쌍을 사용하여 서명되는 경우, 서명은 또한 개인 키를 보유한 당사자만이 서명한 사람임을 증명한다.


JSON 웹 토큰의 구조

JWT는 세 부분으로 구성되며, 각 부분은 점(.)으로 구분된다.

  • 헤더(Header): 토큰 유형과 사용된 암호화 알고리즘 정보를 담고 있다.

  • 페이로드(Payload): 사용자 정보(클레임)를 포함한다.

  • 서명(Signature): 토큰의 무결성을 검증하는 데 사용된다.

따라서 JWT는 일반적으로 다음과 같다.

xxxxx.yyyyy.zzzzz

1. Header

헤더는 일반적으로 두 부분으로 구성된다. 토큰 유형인 JWT와 사용되는 서명 알고리즘(HMAC SHA256 또는 RSA 등)다.

  • 예시 Header:
{
  "alg": "HS256",
  "typ": "JWT"
}

그런 다음, 이 JSON은 Base64Url 로 인코딩되어 JWT의 첫 번째 부분을 형성한다.

2. Payload

토큰의 두 번째 부분은 페이로드로, 클레임들을 포함한다. 클레임은 엔티티(일반적으로 사용자)에 대한 설명과 추가 데이터다. 클레임에는 registered , public , private 클레임의 세 가지 유형이 있다.

registered 클레임

이는 필수는 아니지만 권장되는 미리 정의된 클레임 집합이다. 유용하고 상호 운용 가능한 클레임 세트를 제공한다.

주요 예시:

  • iss (발행자)

  • exp (만료 시간)

  • sub (주제)

  • aud (대상)

클레임 이름이 세 글자로 짧은 이유는 JWT가 간결성을 목표로 하기 때문이다.

public 클레임

JWT 사용자가 자유롭게 정의할 수 있다. 하지만 충돌을 피하기 위해 IANA JSON Web Token Registry에 등록하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 한다.

private 클레임

이는 당사자들 간에 정보를 공유하기 위해 만든 사용자 지정 클레임으로, 등록된 클레임이나 공개 클레임이 아니다.

  • 예시 Payload:
{
  "sub": "1234567890", // regiseted 클레임
  "name": "홍길동", // regiseted 클레임
  "admin": true // private 클레임
}

이 payload는 Base64Url로 인코딩되어 JSON Web Token의 두 번째 부분을 형성한다.

3. Signature

서명(Signature)

JWT의 서명 부분은 헤더(Header)페이로드(Payload)를 인코딩한 값, 비밀 키(secret), 그리고 헤더에 명시된 알고리즘을 사용하여 생성된다. 이 서명은 토큰의 무결성을 검증하고, 발신자가 신뢰할 수 있는지 확인하는 데 사용된다.

서명 생성 방식

예를 들어, HMAC SHA256 알고리즘을 사용하는 경우, 서명은 다음과 같은 방식으로 생성된다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)
  • base64UrlEncode(header): 헤더를 Base64Url로 인코딩
  • base64UrlEncode(payload): 페이로드를 Base64Url로 인코딩
  • secret: 서버만 알고 있는 비밀 키

서명의 역할

  1. 무결성 검증: 토큰이 전송 중에 변경되지 않았음을 확인한다.
  2. 발신자 인증: 개인 키로 서명된 경우, JWT의 발신자가 신뢰할 수 있는지 확인할 수 있다.

인증 과정

HS256를 사용할 때

클라이언트가 로그인을 위해 ID와 비밀번호를 서버에 전송을 하면 서버는 JSON Web Token을 만들어 준다.

JWT를 만들 때 서버는 header, payload, signature를 만든다.

header에는 HS256이라는 정보가 들어 있는데 이는 HS256으로 서명을 했다는 뜻이다.
payload에는 { username: doolchong }
signature에는 header와 payload, 그리고 다른 사람은 모르고 서버만 알고 있는 SECREY_KEY 값을 더한 후 HS256으로 암호화 한다.

HS256 이라는 것은 HMAC(시크릿 키를 포함한 암호화) 이라는 방식으로 SHA256으로 암호화 한다는 것이다. -> 해시 한다는 의미(복호화할 수 없는 고정 길이의 값을 생성하는 과정)

즉, 이렇게 시크릿 키를 포함하여 암호화 한 방식이 HMAC 방식인 것이다.

이 후 각각을 Base64로 인코딩 한다.

이렇게 만들어진 토큰을 인증이 완료된 클라이언트에게 돌려준다.

이렇게 만들어진 토큰은 클라이언트 웹 브라우저의 로컬 스토리지 영역에 저장된다.

이 토큰을 가지고 서버에 나의 개인정보를 달라는 요청을 보낸다고 가정하자

요청을 보낼 때는 저장했던 JWT를 담아서 보낸다.

서버는 JWT를 받아서 우선적으로 JWT가 신뢰할 수 있는 토큰인지 검증을 한다.

우선적으로 Signature에 HS256으로 암호화 된 정보가 ABCD라고 가정한다.

서버 입장에서는 JWT가 유효한 토큰인지 확인하는 것이 중요하다.

그렇다면 서버는 이를 어떻게 확인할까?

우선 header와 payload 그리고 서버가 가지고 있는 시크릿 키를 가지고 똑같이 HS256으로 암호화 해본다. 만약 이 값이 ABCD가 나온다면 이 토큰을 유효한 토큰으로 인식하고 검증을 완료한다.

이후 payload에 있는 유저 정보를 기반으로 DB에서 SELECT 해서 반환하면 된다.

RSA를 사용할 때

RSA를 사용할 때는 header, payload, signature로 구성된 JSON Web Token에서 signature는 header, payload만으로 구성된다.

RSA에서는 공개 키랑 개인 키가 있기 때문에 서버가 개인 키로 잠궈서 signature를 만든다.

이 토큰을 클라이언트가 서버로부터 받아서

다시 서버쪽으로 JWT를 담아서 요청을 보내면

서버는 공개 키로 서명을 검증하여 signature를 열어보면 된다.

근데 보통은 HS256으로 한다.

주의사항

서명된 토큰의 경우, 이 정보는 변조로부터 보호되지만 누구나 읽을 수 있다. 따라서 암호화되지 않은 JWT의 페이로드나 헤더에 비밀 정보를 넣으면 안 된다.

0개의 댓글