JWT (JSON Web Token): 개념 및 원리 완벽 정리
1. 기본 개념: 놀이공원 자유이용권
JWT란 무엇인가?
- 정의: 유저의 정보를 담은 JSON 데이터를 암호화된 서명(Signature)과 함께 URL로 전달 가능한 문자열로 만든 표준(RFC 7519)입니다.
- 비유: "놀이공원 손목 띠(자유이용권)"와 같습니다.
왜 '손목 띠'인가요? (Session vs JWT)
| 구분 | 세션 (Session) 방식 | JWT (Token) 방식 |
|---|---|---|
| 비유 | 회원 명부 | 손목 띠 (자유이용권) |
| 작동 원리 | 직원이 입장할 때마다 장부(서버 DB)를 뒤져서 "이 사람 회원 맞나?" 확인합니다. | 직원은 손님이 찬 손목 띠만 봅니다. 장부를 볼 필요가 없습니다. |
| 장점 | 보안이 강력함 (서버가 통제) | 서버 부하가 적음. (장부 확인할 필요 없음) |
| 단점 | 사용자가 많아지면 장부 확인 줄이 길어짐 (서버 과부하) | 손목 띠를 잃어버리면 누구나 쓸 수 있음 (탈취 위험) |
2. JWT의 구조 (3단 케이크)
JWT는 점(.)으로 구분된 3덩어리의 문자열로 이루어져 있습니다.
aaaaaa.bbbbbb.cccccc
1) Header (헤더) - "빨간색 포장지"
- 내용: "나 어떤 알고리즘으로 서명했어" (예:
HS256) - 역할: 토큰의 타입과 암호화 방식을 알려줍니다.
2) Payload (페이로드) - "케이크(내용물)"
- 내용: 실질적인 데이터. (사용자 ID, 이름, 등)
- 특징: 누구나 내용을(Base64 디코딩으로) 열어볼 수 있습니다.
- 주의: 비밀번호, 주민번호 같은 민감한 정보는 절대 넣으면 안 됩니다! (투명한 봉투와 같습니다)
3) Signature (서명) - "봉인 씰(도장)"
- 내용:
Header+Payload+서버만의 비밀키를 섞어서 만든 암호문. - 역할: 위변조 방지. 누군가 Payload(내용물)를 몰래 고치면, 이 서명과 맞지 않게 되어 즉시 들통납니다.
3. 토큰은 왜 중요한가요? (Identity)
"토큰은 곧 '나' 자신입니다."
서버는 요청을 받을 때마다 "이게 누구지?"를 확인하지 않습니다.
대신 "이 토큰이 진짜인가?"만 확인합니다.
- 디지털 열쇠: 호텔 카드키와 같습니다. 카드키를 주운 사람은 누구든 내 방에 들어갈 수 있습니다. 서버는 카드키를 든 사람이 '진짜 주인'인지 '도둑'인지 구별하지 못합니다.
- 권한의 증표: 이 토큰 하나로 '내 사진 삭제', '결제', '비밀번호 변경' 등 나로서 할 수 있는 모든 권한이 생깁니다.
- 결론: 토큰을 잃어버리는 것은 내 신분증과 집 열쇠, 지갑을 통째로 넘겨주는 것과 같습니다. 그래서 "어디에 안전하게 보관할 것인가"가 가장 중요한 이슈가 됩니다.
3. JWT는 어떻게 믿을 수 있나요? (무결성)
시나리오: 해커의 조작 시도
- 발급: 서버가 철수에게 "철수는 일반 유저임"이라고 쓴 JWT를 발급해줍니다. 서명은
(내용+비밀키)로 만들어졌습니다. - 조작: 해커가 중간에 토큰을 가로채서 "철수는 관리자(Admin)임"이라고 Payload를 고칩니다.
- 전송: 해커가 조작된 토큰을 서버에 보냅니다.
- 검증 (서버의 방어):
- 서버는 토큰을 받자마자 서명(Signature)을 다시 계산해봅니다.
받은 내용("관리자")+비밀키=새로운 서명 B- 하지만 토큰에 붙어있는 건
원래 서명 A입니다. - 불일치!: 서버는 "이 녀석, 내용물을 건드렸구나!"라고 바로 알아채고 요청을 거부합니다.
핵심: 해커는 내용은 고칠 수 있어도, 서버의 비밀키를 모르기 때문에 그에 맞는 유효한 서명을 새로 만들어낼 수 없습니다.
4. 자주 묻는 질문 (FAQ) & 보안 시나리오
Q. "JWT를 해킹한다"는 게 무슨 뜻인가요?
해킹에는 크게 두 가지 종류가 있습니다.
1) 위변조 (Tampering) - "내용 고치기"
- 시도: 해커가 내 토큰의 "일반 유저" 정보를 "관리자"로 몰래 고쳐서 서버에 보냅니다.
- 방어: 불가능합니다. 서버의 비밀키(Secret Key)가 없으므로, 내용을 고치는 순간 서명(Signature)이 깨져서 서버가 바로 거부합니다. (이건 안전합니다!)
2) 탈취 (Theft) - "훔쳐서 그대로 쓰기"
- 시도: 해커가 피시방 컴퓨터나 악성 스크립트(XSS)를 통해 사용자의 정상적인 토큰(손목 띠)을 복사해갑니다.
- 위험: 해커가 이 토큰을 서버에 내밀면, 서버는 "어? 정당한 손목 띠네?" 하고 통과시켜 줍니다. (이게 진짜 위험합니다.)
- 해결책:
- 유효기간을 짧게(Short-lived) 만듭니다. (예: 5분). 해커가 훔쳐도 5분 뒤면 못 쓰게 됩니다.
- 그런데 5분마다 로그인하면 귀찮잖아요? → 그래서 Refresh Token이 등장합니다.
5. 저장소 전략: 어디에 숨겨야 안전할까? (Storage)
토큰을 클라이언트(브라우저)의 어디에 저장하느냐는 보안의 핵심입니다.
1) LocalStorage (로컬 스토리지)
- 특징: 브라우저에 있는 간단한 저장소. 자바스크립트로 쉽게 넣고 뺄 수 있습니다. (
localStorage.getItem()) - 장점: 개발이 매우 편리합니다.
- 치명적 단점 (XSS 공격): 해커가 게시판에 악성 자바스크립트를 심어놓으면, 그 스크립트가 내 로컬 스토리지의 토큰을 훔쳐갈 수 있습니다. (가장 흔한 해킹 방식)
- 권장 여부: Access Token은 편의상 여기에 두기도 하지만, Refresh Token은 절대로 여기에 두면 안 됩니다.
2) HttpOnly Cookie (쿠키)
- 특징: 서버가 브라우저에게 "이거 저장해둬"라고 명령하는 쿠키입니다. 단,
HttpOnly옵션을 붙입니다. - 장점 (보안): 자바스크립트로 접근이 불가능합니다. 해커가 악성 스크립트를 심어도 쿠키를 읽을 수 없습니다. (브라우저만 내부적으로 서버에 보낼 때 사용함)
- 권장 여부: [Best Practice] Refresh Token은 무조건 여기에 저장해야 합니다.
3) 최적의 조합 (Best Practice)
| 종류 | 저장 위치 | 이유 |
|---|---|---|
| Access Token | 메모리(변수) or LocalStorage | API 통신에 자주 써야 하므로 접근이 쉬운 곳에 둡니다. (탈취돼도 수명이 짧아 괜찮음) |
| Refresh Token | HttpOnly Cookie | 자바스크립트 접근을 원천 차단하여, 해커가 훔쳐갈 수 없게 만듭니다. |
요약: "자주 쓰는 건(AT) 주머니에, 정말 중요한 건(RT) 은행 금고(HttpOnly Cookie)에."
6. Refresh Token (리프레시 토큰) 전략
"짧은 수명의 출입증과 긴 수명의 재발급권"
기본 구조
로그인 시 서버는 두 개의 토큰을 줍니다.
- Access Token (액세스 토큰):
- 용도: 실제 출입증 (API 요청용).
- 수명: 아주 짧음 (예: 30분).
- 특징: 탈취당해도 금방 만료되니 피해가 최소화됩니다.
- Refresh Token (리프레시 토큰):
- 용도: "액세스 토큰이 만료되면 새거 주세요" 할 때 쓰는 재발급권.
- 수명: 아주 김 (예: 2주).
- 특징: 평소에는 금고(DB)나 안전한 곳(HttpOnly Cookie)에 두고 잘 안 꺼냅니다.
작동 흐름 (시나리오)
- 로그인: 유저가
Access Token(30분)+Refresh Token(2주)을 받습니다. - 사용: 유저는
Access Token만 보여주고 신나게 놉니다. - 만료: 30분 뒤, 입구에서 "손님, 이 출입증 기한 지났는데요?"(401 Error) 하고 막습니다.
- 갱신 (Silent Refresh):
- 유저(브라우저)는 당황하지 않고, 가방 깊숙한 곳에서
Refresh Token을 꺼내 서버에 보냅니다. "재발급권 여기요." - 서버는 "재발급권 맞네. 자, 새로운
Access Token(30분짜리)줄게." 합니다.
- 유저(브라우저)는 당황하지 않고, 가방 깊숙한 곳에서
- 지속: 유저는 다시 로그인할 필요 없이 계속 서비스를 이용합니다.
왜 이렇게 하나요?
- 보안과 편의성, 두 마리 토끼를 잡기 위해서입니다.
- Access Token을 자주 훔쳐 가는 길거리에 내놓더라도(API 통신), 수명이 짧아 해커가 오래 못 씁니다.
- Refresh Token은 재발급할 때만 가끔 꺼내니 탈취 위험이 적고, 만약 탈취당하면 서버가 해당 Refresh Token을 정지(DB 삭제)시키면 됩니다.
5. 결론: 언제 써야 할까?
- 모바일 앱: 로그인 상태 유지가 필요할 때 최고입니다.
- MSA (마이크로서비스): 여러 서버가 공통의 비밀키만 공유하면, 별도의 인증 서버를 거치지 않고도 각자 인증 처리가 가능해 효율적입니다.