토큰
당사자 간에 안전하게 정보를 JSON 형태로 전송하기 위해 정의된 자체 수용적(Self-Contained) 암호화 토큰 스펙.
— RFC 7519 JSON Web Token 명세서
"서버의 메모리 부담을 클라이언트에게 외주 준 결과물. 대신 보안 리스크도 같이 외주 처리됐다." 토큰이 한 번 유출되면 그 유저가 로그아웃을 백번 눌러도 해커는 만료 전까지 프리패스다.(...)
1. 개요
서버가 클라이언트의 상태를 저장하지 않는 무상태(Stateless) 아키텍처를 실현하기 위해 사용하는 암호화된 증명서 조각이다. 주로 JWT(JSON Web Token) 스펙이 업계 표준으로 군림하고 있다. 유저 정보와 만료일, 권한 등을 통째로 인코딩한 뒤 서버만 아는 비밀키로 서명(Signature)하여 유저에게 던져준다. 유저는 매 요청마다 이 토큰을 HTTP 헤더에 얹어서 날린다.(...)
2. 무상태성의 축복과 무효화 불가라는 양날의 검
토큰 방식은 세션과 달리 서버 메모리를 단 1바이트도 쓰지 않는다. 서버는 유저가 보낸 토큰의 비밀키 서명이 올바른지만 수학적으로 검증하고 바로 오케이(인증)를 때리기 때문에, 서버를 수천 대 수만 대로 늘리는 스케일 아웃 환경에서 최강의 위력을 발휘한다. 그러나 치명적인 단점이 있으니, 바로 한번 내뱉은 토큰은 유효기간이 끝날 때까지 서버가 통제할 수 없다는 점이다. 만약 어떤 악당이 유저의 액세스 토큰(Access Token)을 훔쳐 가면, 진짜 유저가 비밀번호를 바꾸고 눈물을 흘려도 서버 입장에서는 서명이 맞기 때문에 정상 유저로 취급할 수밖에 없다.1 이를 보완하기 위해 수명이 30분짜리인 숏텀 액세스 토큰과 이를 재발급해 주는 롱텀 리프레시 토큰(Refresh Token)을 섞어 쓰는 눈물겨운 복합 똥쇼 분투기가 현대 웹 개발의 표준 포맷이 되었다.(...)
3. 관련 밈 및 드립
3.1. Bearer가 도대체 뭔데
네트워크 탭을 열어 Authorization: Bearer eyJhbGci... 형태의 헤더를 처음 마주한 주니어 개발자들이 고개를 갸우뚱하는 단골 밈이다. 'Bearer'는 이 토큰을 '소지한 사람'에게 권한을 주겠다는 뜻의 프로토콜 규약인데, 수많은 코딩 노예들이 영문도 모른 채 구글링이나 AI 프롬프트가 뱉어준 코드를 기계적으로 복사 붙여넣기(복붙)하며 영원히 스펠링을 틀려 에러를 내는 지점이다.
3.2. JWT는 암호화가 아닙니다
신입들이 많이 치는 사고 중 하나로, JWT 내부의 페이로드(Payload) 내용물이 암호화되어 숨겨진 줄 알고 비번이나 주민번호를 그대로 때려 박았다가 시니어에게 등짝 스매시를 맞는 밈이다. JWT는 단지 변조를 막기 위해 '서명'을 한 것일 뿐, 내용물은 누구나 디코딩 사이트에서 1초 만에 알맹이를 까볼 수 있는 단순 Base64 인코딩 구조이기 때문이다.
4. 여담
- 로컬 스토리지 vs 쿠키: 토큰을 브라우저 어디에 저장할 것인가는 프론트엔드와 백엔드 개발자 사이의 영원한 키보드 배틀 주제다. XSS 공격에 털릴 것인가, CSRF 공격에 낚일 것인가의 가혹한 밸런스 게임이다.
- 토큰 비대화: 토큰 페이로드에 유저 프로필 이미지 URL, 주소, 닉네임 등 온갖 정보를 욕심내어 담다 보면 토큰 용량이 커져 배보다 배꼽이 더 큰 네트워크 패킷 낭비가 발생한다.
- 블랙리스트 편법: 토큰 탈취 대응을 위해 만료 전 토큰을 강제 만료시키는 '블랙리스트' 기능을 서버에 구현하곤 하는데, 이걸 구현하는 순간 서버에 저장소가 필요해져서 토큰의 최대 장점인 무상태성(Stateless)이 퇴색되는 모순이 발생한다.
5. 관련 문서
각주
-
실제로 이 마법의 증명서 덕분에 서버 개발자들은 편해졌지만, 프론트엔드 개발자들은 토큰이 만료될 때마다 유저 모르게 백엔드로 리프레시 요청을 찔러넣는 인터셉터(Interceptor) 로직을 짜느라 피똥을 싼다.(...) ↩