[기술 딥다이브] JWT: 구조와 작동 방식, 그리고 한계


한 줄 요약: JWT는 헤더·페이로드·서명을 base64url로 인코딩해 점으로 연결하고 서명한 토큰으로, 서버가 세션 저장 없이 서명 검증만으로 인증하게 만든다(stateless).

로그인을 하면 서버가 토큰을 발급하고, 이후 요청마다 그 토큰을 첨부하여 보내는 인증 방식이 JWT(JSON Web Token)입니다. xxxxx.yyyyy.zzzzz처럼 점 세 개로 구분된 긴 문자열인데, 그 안에 명확한 구조가 존재합니다. 풀어 설명하겠습니다.

세 부분: 헤더, 페이로드, 서명

JWT는 점(.)으로 구분된 세 부분으로 구성됩니다.

  • 헤더(header): 토큰의 타입(JWT)과 서명 알고리즘(HS256 등)을 포함합니다.
  • 페이로드(payload): 클레임(claims)이라 부르는 정보로, 사용자 ID, 만료 시간, 발급자 등이 포함됩니다.
  • 서명(signature): 헤더와 페이로드를 합쳐서 비밀 키로 서명한 값입니다.

base64url 인코딩: URL에 안전한 인코딩

세 부분은 각각 base64url로 인코딩됩니다. 일반 base64와 유사하지만 +-로, /_로 대체하고 = 패딩을 생략합니다. URL에 포함되어도 깨지지 않도록 설계된 것입니다. 그래서 JWT는 HTTP 헤더나 URL 파라미터에 실어서 전송할 수 있습니다.

서명 알고리즘: HMAC vs RSA/ECDSA

서명은 토큰이 변조되지 않았음을 보증합니다. 알고리즘은 크게 두 가지로 나뉩니다.

  • HMAC(대칭키): HS256 같은 방식. 발급자와 검증자가 동일한 비밀 키를 공유합니다. 빠르고 단순하지만, 키가 유출되면 누구나 토큰을 위조할 수 있습니다.
  • RSA/ECDSA(비대칭키): RS256 같은 방식. 개인 키로 서명하고 공개 키로 검증합니다. 여러 서버가 검증해야 하는 환경에 적합합니다.

stateless 인증: 서버가 상태를 저장하지 않는다

JWT의 핵심은 stateless입니다. 서버가 세션을 DB나 메모리에 저장하지 않아도, 토큰 안에 필요한 정보가 모두 포함되어 있습니다. 서버는 토큰의 서명만 검증하면 됩니다. 그래서 여러 서버가 하나의 토큰을 검증할 수 있어 확장성이 좋습니다.

한계: 암호화가 아니며, 폐기가 어렵다

JWT에 대한 가장 큰 오해는 ’암호화되어 있다’는 것입니다. 그렇지 않습니다. base64url은 인코딩이지 암호화가 아닙니다. 누구나 토큰을 디코딩하여 페이로드를 읽을 수 있습니다. 비밀번호나 민감한 정보를 페이로드에 포함해서는 안 됩니다.

또한 서명은 변조 방지만 수행할 뿐, 토큰 자체를 폐기(revoke)하기는 어렵습니다. 만료 시간 이전에 강제 로그아웃을 처리하려면 서버가 별도로 블랙리스트를 관리해야 하며, 이는 stateless의 장점을 상쇄합니다.

참고: alg: none 취약점. 서명 알고리즘을 none으로 설정하면 서명 없이도 토큰이 통과하는 구버전 라이브러리가 존재했습니다. 검증 시 알고리즘을 명시적으로 지정해야 합니다.

어떻게 연결되는가

한 줄로 요약하면: header, payload, signature 세 부분을 base64url로 인코딩하여 점으로 연결하고, 비밀 키(또는 개인 키)로 서명한 토큰입니다. 서버는 stateless 방식으로 토큰만 검증하면 인증이 완료됩니다. 다만 페이로드는 누구나 읽을 수 있고 폐기가 어려우므로, 민감 정보는 포함하지 말고 만료 시간을 짧게 설정하는 것이 핵심입니다.

출처: RFC 7519: JSON Web Token (JWT) · jwt.io: JSON Web Token Introduction · 위키백과: JSON Web Token