JSON Web Token을 디코딩해서 헤더와 클레임을 읽고 만료 여부를 확인합니다. 토큰을 기록할지도 모르는 외부 사이트에 붙여넣지 않아도 됩니다.
JWT는 점으로 구분된 세 개의 base64url 조각이고, 앞의 둘은 암호화된 것이 아니라 인코딩만 되어 있습니다. 토큰을 가진 사람은 누구나 그 안의 클레임을 읽을 수 있습니다. 민감한 값을 담기 전에 알아 둘 만한 사실입니다. 디코딩은 요청이 왜 거부됐는지 확인하는 방법이기도 합니다. 만료된 exp, 맞지 않는 대상(aud), 예상과 다른 발급자(iss) 같은 것들입니다.
이 페이지는 헤더와 페이로드를 해석하고 exp, iat, nbf를 원래의 epoch 숫자와 함께 읽을 수 있는 날짜로 보여 주며, 토큰이 만료됐는지를 분명히 표시합니다. 서명은 검증하지 않습니다. 검증하려면 발급자의 키가 필요하고, 확인할 수 없는 서명을 확인했다고 말하는 디코더는 아예 시도하지 않는 쪽보다 나쁘기 때문입니다.
헤더의 alg 필드는 역사적인 취약점이 모여 있는 자리이고, 토큰을 받았을 때 가장 빨리 확인할 수 있는 지점이기도 합니다. 과거에는 토큰이 그렇게 적혀 있다는 이유만으로 alg: none 을 받아들이고 검증을 건너뛰는 서버가 있었습니다. 알고리즘 혼동 공격은 RS256 토큰을 HS256으로 다시 서명하되 발급자의 공개키를 HMAC 비밀키로 쓰는 방식입니다. 공개키이므로 공격자가 이미 가지고 있는 값입니다. 둘 다 서버가 검사할 토큰에서 답을 읽는 대신 어떤 알고리즘을 받아들일지 미리 정해 두는 것으로 막힙니다. 헤더를 그대로 볼 수 있으면 토큰이 예상과 다른 방식으로 서명되어 왔다는 사실을 알아챌 수 있습니다.
등록된 클레임은 짧은 목록이고 각각 다른 방식으로 실패합니다. exp와 nbf는 유효 구간을 정하고, iat는 발급 시각을, iss와 aud는 누가 만들었고 누구를 위한 것인지를, sub는 대상을 나타냅니다. 시간 값은 모두 밀리초가 아니라 초 단위입니다. 그래서 exp를 밀리초로 적은 토큰은 수만 년 뒤에 만료되는 것처럼 보이는데, 이 페이지는 원래 숫자 옆에 날짜를 함께 표시하므로 그 실수가 곧바로 드러납니다. 발급하는 기계와 검증하는 기계의 시계가 조금 어긋나는 것도 흔한 원인입니다. 만료됐다거나 아직 유효하지 않다는 이유로 몇 초 차이에서 토큰이 거부됩니다.
JWT는 회수할 수 없습니다. 결함이 아니라 설계의 결과입니다. 누구에게도 묻지 않고 서버가 스스로 검증할 수 있다는 것이 존재 이유인데, 그것은 곧 exp가 지나기 전에 그 토큰이 무효가 됐다고 서버에게 알려 줄 방법이 없다는 뜻이기도 합니다. 모든 기기에서 로그아웃시키려면 차단 목록을 두거나, 수명을 짧게 하고 갱신 토큰을 붙여야 합니다. 어느 쪽이든 토큰이 없애려 했던 서버 측 상태를 다시 들여옵니다. 크기는 좀 더 조용한 제약입니다. 헤더로 오가는 토큰은 모든 요청에 붙고, 역할과 권한을 클레임에 밀어 넣다 보면 웹 서버에서 흔한 8KB 헤더 한계에 닿을 수 있습니다.
헤더의 kid 필드는 발급자가 서명 키를 교체하기 때문에 존재합니다. 어떤 키로 서명했는지를 가리키므로, 여러 키를 가진 검증자가 하나씩 시도하는 대신 맞는 것을 바로 고를 수 있고, 발급자는 이미 유통 중인 토큰을 무효로 만들지 않고도 새 키를 공개하고 옛 키를 물릴 수 있습니다. kid 가 발급자의 현재 키 목록에 없는 토큰은 위조된 것이라기보다 오래된 것인 경우가 많습니다. 여기서 그 값을 확인하는 것이, 있지도 않은 검증 버그를 찾아 나서기 전에 예상한 키로 서명된 토큰이 맞는지 확인하는 방법입니다.
아니요. base64url 디코딩과 JSON 파싱을 브라우저에서 처리합니다. 그래도 운영 토큰은 살아 있는 자격증명이므로 취급에 주의하세요.
아니요. 검증에는 서명 키가 필요한데 그 키는 서버 밖으로 나가면 안 됩니다. 백엔드 라이브러리를 쓰세요.
대개 복사가 잘렸거나 앞에 "Bearer "가 딸려온 경우입니다. JWT는 점으로 구분된 세 조각이어야 합니다.