JWT(JSON Web Token)은 정보 수신/송신자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 간결하고 Self-contained한 방법을 정의하는 개방형표준(RFC 7519)이다. 이 정보는 디지털 서명되어 있으므로 확인 및 신뢰가 가능하다. JWT는 Secret( HMAC 알고리즘 사용)을 사용 하거나 RSA 또는 ECDSA를 사용하는 공개/개인 키 쌍을 사용하여 서명할 수 있다.
JWT를 암호화하여 수신/송신자 간에 기밀도 제공할 수 있지만, 서명된 토큰에 초점을 맞출 것이다. 서명된 토큰은 해당 토큰에 포함된 클레임의 무결성을 확인할 수 있는 반면, 암호화된 토큰은 다른 당사자로부터 해당 클레임을 숨길 수 있다. 공용/개인 키 쌍을 사용하여 토큰에 서명할 때 서명은 개인 키를 보유한 당사자만 서명했음을 증명한다.
다음은 JSON Web Token이 유용하게 사용되는 몇 가지 시나리오 이다.
간결한 형태의 JSON Web Token은 점( . )으로 구분된 세 부분으로 구성되며 다음과 같다.
aaaaa[Header].bbbbbb[payload].ccccc[Signature]
Header 는 두가지의 정보를 지니고 있습니다.
typ: 토큰의 타입을 지정합니다. 바로 JWT
이죠.
alg: 해싱 알고리즘을 지정합니다. 해싱 알고리즘으로는 보통 HMAC SHA256
혹은 RSA
가 사용되며, 이 알고리즘은, 토큰을 검증 할 때 사용되는 signature 부분에서 사용됩니다.
{
"typ": "JWT",
"alg": "HS256"
}
Payload 부분에는 토큰에 담을 정보가 들어있다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(claim) 이라고 부르고, 이는 name / value 의 한 쌍으로 이뤄져있습니다. 토큰에는 여러개의 클레임 들을 넣을 수 있음
클레임 의 종류는 다음과 같이 크게 세 분류로 나뉘어져있습니다:
등록된 (registered) 클레임,공개 (public) 클레임,비공개 (private) 클레임
등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임들입니다. 등록된 클레임의 사용은 모두 선택적 (optional)이며, 이에 포함된 클레임 이름들은 다음과 같습니다:
iss
: 토큰 발급자 (issuer)sub
: 토큰 제목 (subject)aud
: 토큰 대상자 (audience)exp
: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.nbf
: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.iat
: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age
가 얼마나 되었는지 판단 할 수 있습니다.jti
: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.공개 클레임들은 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 합니다. 충돌을 방지하기 위해서는, 클레임 이름을 URI 형식으로 짓습니다.
{
"https://velopert.com/jwt_claims/is_admin": true
}
등록된 클레임도아니고, 공개된 클레임들도 아닙니다. 양 측간에 (보통 클라이언트 <->서버) 협의하에 사용되는 클레임 이름들입니다. 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야합니다.
{
"username": "velopert"
}
{
"iss": "velopert.com",
"exp": "1485270000000",
"https://velopert.com/jwt_claims/is_admin": true,
"userId": "11028373727102",
"username": "velopert"
}
JSON Web Token 의 마지막 부분은 바로 서명(signature) 입니다. 이 서명은 헤더의 인코딩값과, 정보의 인코딩값을 합친후 주어진 비밀키로 해쉬를 하여 생성합니다.
서명 부분을 만드는 슈도코드(pseudocode)의 구조는 다음과 같습니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
이렇게 만든 해쉬를, base64
형태로 나타내면 됩니다 (문자열을 인코딩 하는게 아닌 hex
→ base64
인코딩을 해야합니다)
authentication(인증)에서 사용자가 자격 증명을 사용하여 성공적으로 로그인하면 JSON Web Token이 반환된다. 토큰은 자격 증명이므로 보안 문제를 방지하기 위해 세심한 주의르르 기울여야 한다. 일반적으로 토큰을 필요 이상으로 오래 보관해서는 안된다.
또한 보안이 취약하기 때문에 민감한 세션 데이터를 브라우저 저장소에 저장해서는 안된다.
사용자가 보호된 경로 또는 리소스에 액세스하려고 할 때마다 사용자 에이전트는 일반적으로 Bearer 스키마를 사용하여 Authorization 헤더에서 JWT를 보내야 한다. Header의 내용은 다음과 같아야 한다.
Authorization: Bearer <token>JAVASCRIPT
이는 특정 경우에 stateless(상태 비저장) Authorization 매커니즘일 수 있다. 서버의 보호된 경로가 Authorization header(인증헤더)에서 유효한 JWT를 확인하고, 유효한 JWT가 있는 경우 사용자는 보호된 리소스에 액세스할 수있다. JWT에 필요한 데이터가 포함되어 있는 경우, 데이터베이스를 조회하여 특정 작업을 수행할 필요가 줄어들 수 있지만, 모든 경우가 그런 것은 아니다.
토큰이 Authorization header(인증헤더)에서 전송되는 경우 CORS(Cross-Origin Resource Sharing)는 쿠키를 사용하지 않으므로 문제가 되지 않는다.
SWT(Simple Web Tokens) 및 SAML(Security Assertion Markup Language Tokens)과 비교할 때 JWT(JSON Web Tokens)의 이점에 대해 이야기해 본다.
JSON은 XML보다 덜 장황하기 때문에 인코딩될 때 크기도 작아져 JWT가 SAML보다 더 간결해진다. 따라서 JWT는 HTML 및 HTTP 환경에서 전달하기에 좋은 선택이다.
보안 측면에서 SWT는 HMAC 알고리즘을 사용하는 공유 secret로만 대칭적으로 서명할 수 있다. 그러나 JWT 및 SAML 토큰은 서명을 위해 X.509 인증서 형식의 public/private key 쌍을 사용할 수 있다. 모호한 보안 허점을 도입하지 않고 XML 디지털 서명으로 XML에 서명하는 것은 JSON 서명의 단순성과 비교할 때 매우 어렵다.
JSON Parser는 객체에 직접 매핑되기 때문에 대부분의 프로그래밍 언어에서 일반적이다. 반대로 XML에는 자연스러운 document-to-object 매핑이 없다. 따라서 SAML보다 JWT로 작업하기가 더 쉽다.
사용에 관해서는 JWT가 인터넷 규모로 사용된다. 이는 여러 플랫폼, 특히 모바일에서 JSON Web Token의 클라이언트 측 처리 용이성을 강조한다.