JWT란?
JWT(Json Web Token)은 당사자 간에 정보를 JSON 개체로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다.
디지털 서명이 되어 있어 신뢰할 수 있습니다.
아래 항목과 같은 공개/개인 키 쌍을 통한 암호화 알고리즘을 사용하여 서명할 수 있습니다.
- HMAC
- RSA
- ECDSA
당사자 간의 보안을 제공하며 서명된 토큰에 초점을 맞춥니다. 서명된 토큰은 그 안에 포함된 클레임의 무결성 확인이 가능하지만 암호화된 토큰은 다른 당사자에게 클레임을 숨깁니다.
공개/개인 키 쌍을 사용하여 토큰에 서명하면 개인 키를 소유한 당사자만이 서명한 당사자임을 증명합니다.
사용처?
다음과 같은 시나리오에 JWT를 사용합니다.
- 승인(Authorization) : 가장 일반적인 시나리오로 사용자 로그인 시 후속 요청에 JWT가 포함되어 사용자가 해당 토큰으로 허용되는 라우트, 서비스 및 리소스에 접근할 수 있습니다.
SSO(Single Sign On)는 오버헤드가 적고 다양한 도메인에서 쉽게 사용할 수 있어 JWT를 널리 사용한다. - 정보 교환(Information Exchange) : JWT는 정보 교환에 좋은 방법으로 공개/개인 키 쌍을 통한 JWT에 서명할 수 있어 보낸 사람이 누구인지 확인 할 수 있으며 헤더 및 페이로드를 통해 계산하므로 위/변조를 확인 할 수 있습니다.
JWT 구조
압축된 형태의 JWT는 점(.)으로 구분되 세 부분으로 구성됩니다.
- Header (헤더)
- Payload (페이로드)
- Signature (서명)
일반적으로 이와 같습니다.
xxxxx.yyyyy.zzzzz
(1) Header (헤더)
Header는 일반적으로 토큰 유형과 사용되는 서명 알고리즘(ex: HMAC, SHA256, RSA)의 두 부분으로 구성됩니다.
{
"alg": "HS256",
"typ": "JWT"
}
이후 이 JSON 데이터는 Base64Url로 인코딩되어 JWT의 첫 번째 부분을 구성합니다.
(2) Payload (페이로드)
클레임을 포함하는 페이로드로 클레임은 엔티티(일반적으로 사용자) 및 추가 데이터에 대한 설명입니다.
클레임은 아래와 같이 3가지 유형이 있습니다.
- 등록된 클레임 : 유용하고 상호 운용 가능한 클레임 집합을 제공하기 위해 권장되는 미리 정의된 클레임 집합입니다.
iss(발행자), exp(만료 시간), sub(주제), aud(청중) 등이 있습니다. - 공개 클레임 : JWT를 사용하는 주체가 원하는 대로 정의할 수 있습니다. 그러나 충돌을 방지하려면 IANA JSON 웹 토큰 레지스트리 에 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 합니다.
- 비공개 클레임 : 사용에 동의한 당사자 간에 정보를 공유하기 위한 맞춤 클레임으로 등록 되거나 공개된 클레임이 아닙니다.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
이후 페이로드는 Base64Url로 인코딩되어 JWT의 2번째 부분을 구성합니다.
서명된 토큰의 경우 변조로부터 보호되지만 누구나 읽을 수 있습니다. 암호화되지 않은 경우 JWT에 비밀 정보를 넣지 마세요.
(3) Signature(서명)
서명 부분은 인코딩된 Header + Payload, Secret(키), Header의 알고리즘을 이용한 암호화 값입니다. 예시는 다음과 같습니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
서명은 JWT가 변조되지 않았는지 확인하며, 개인 키로 서명된 경우 JWT의 보낸 사람이 누구인지 확인할 수도 있습니다.
해당 부분은 key가 없으면 복호화할 수 없어 보안상 안전하다는 특징을 가진다.
Header + Payload + Signature
작성된 Header, Payload, Signature를 기반으로 3개의 점으로 구분된 JWT를 생성합니다.
이는 Base64-URL 문자열로 SAML과 같은 XML 기반 표준과 비교해 더 간결합니다.
jwt.io의 디버거 를 통해 JWT를 디코딩, 인코딩해 볼 수 있습니다.
참고로 Signature 부분의 your-256-bit-secret 부분은 주의해서 작성하도록 한다. (무작정 따라하다 무심결에 넣는 경우도..)
JWT 동작 방식
인증 시 사용자가 자격 증명을 사용하여 로그인에 성공하면 JWT가 반환됩니다.
토큰은 자격 증명으로 보안 문제에 대한 세심한 주의가 필요하며, 일반적으로 토큰을 필요로 한 시간보다 오래 보관해서는 안 됩니다.
또한 보안이 부족하므로 민감한 세션 데이터를 브라우저 저장소에 저장해서는 안 됩니다.
사용자가 특정 요소에 액세스하려고 할 때마다 사용자는 Bearer 스키마를 사용하여 Authorization 헤더에 JWT를 포함하여 요청을 보내야 합니다.
Authorization: Bearer <token>
서버는 Authorization에서 유효한 JWT를 확인하고, 유효한 JWT가 있으면 사용자는 보호된 리소스에 액세스할 수 있습니다.
JWT에 필요한 데이터를 포함한 경우 DB 쿼리의 필요성이 경우에 따라 줄거나 늘어납니다.
*HTTP 헤더를 사용할 경우 토큰이 너무 커지지 않도록해야 하고 일부 서버는 헤더에 8KB 이상을 허용하지 않습니다.
많은 정보를 포함하는 경우 Auth0 Fine-Grained Authorization 와 같은 솔루션이 필요할 수 있습니다.
토큰이 Authorization 헤더로 전송되면 쿠키를 사용하지 않아 CORS(Cross-Origin Resoure Sharing)가 문제되지 않습니다.
JWT의 활용
JWT를 단독으로 사용할 경우 한번 생성된 JWT는 유효기간이 지나기 전까지는 어디서나 사용 가능하기 때문에 탈취시 보안에 취약해지는 단점이 있습니다.
그러나 이러한 단점을 극복하기 위해 유효기간이 짧은 Access Token 과 비교적 유효기간이 긴 Refresh Token을 통해 상호 보완합니다.
- Access Token : 클라이언트가 서버와 통신하기 위해 필요한 메인 자원으로 해당 토큰을 기반으로 서버의 리소스에 접근합니다. 또한 유효기간이 짧게 설정되는 특징이 있습니다.
- Refresh Token : Access Token의 재 발급을 위한 토큰으로 Access Token 만료시 해당 토큰을 사용하여 토큰을 재 발급 받습니다. 또한 유효기간이 Access Token보다 길게 설정되는 특징이 있습니다.
이러한 Access Token, Refresh Token의 활용은 만일 Access Token이 탈취당하더라도 공격자는 짧은 Access Token으로 인해 금방 권한을 잃고 다시 탈취를 시도하게 됩니다.
만일 이러한 점을 극복하고자 exp(유효기간) 값을 변조시키더라도 이미 암호화된 Signature 값은 변하지 않기 때문에 서버는 접근 권한을 반환하지 않습니다.
하지만 통신 빈도가 낮은 Refresh Token 또한 탈취당할 가능성이 있습니다. 이와 같은 이유로 나온 대책이 Refresh Token Rotation으로 Refresh Token을 통한 Access Token 재 발급 때마다 Refresh Token도 새로 발급받는 것입니다.
이러한 방법으로 Refresh Token또한 만료 기간이 짧게(재생성 이전에 생성된 토큰은 재사용 불가) 되어 탈취의 위험성이 줄어들게 됩니다.
JWT 인증 흐름
가장 보편적인 사용처인 로그인을 예시로 들어 보겠습니다.
- 클라이언트가가 로그인을 요청합니다.
- 서버가 요청을 받고 Access Token과 Refresh Token을 발급한 뒤 사용자에게 반환합니다.
- 반환된 각각의 Access Token, Refresh Token을 로컬에 저장합니다.
- 이후 서버로부터 반환된 JWT를 통해 API와 같은 다른 리소스에도 접근할 수 있습니다.
- 일정 시간이 지나고 Access Token이 만료됩니다.
- Access Token이 유효하지 않으므로 클라이언트는 권한을 잃어 클라이언트 요청에 대해 401(Unauthorized) 를 반환합니다.
- 헤더에 Access Token 대신 Refresh Token을 넣어 Access Token의 재발급을 요청합니다.
- 새로운 Access Token 및 Refresh Token을 반환받습니다.
- Refresh Token이 만료되지 않았을 경우 3부터 다시 진행됩니다.
- Refresh Token도 만료되었을 경우 서버는 401(Unauthorized) 를 반환하고 클라이언트는 재로그인이 필요하게 됩니다.
JWT 장단점
장점
- 인증에 필요한 모든 정보를 담고 있어 별도의 저장소가 필요하지 않음
- Signature를 통한 데이터 위변조 방지
- 확장성 좋음
- 서버는 무상태(StateLess) 하게 됨
- OAtuh의 경우 소셜 계정(Googla, Facebook 등) 타 웹 서비스에도 로그인 가능
단점
- 토큰의 길이가 쿠키/세션과 비교해 상대적으로 길어 요청이 많을수록 네트워크 부하가 큼
- Payload에는 중요한 정보를 담을 수 없음
- 토큰 탈취시 대처가 어려움
참고
주요 키워드
#JWT
#Access Token #Refresh Token #Refresh Token Rotation