내가 아는 JWT의 모든 것을 정리해봤습니다. 마지막에는 공부하면서 궁금했던 질문들 정리했습니다. 참고해주세요~
비연결성 (Connectioneless)
: 요청과 응답을 한 번 주고 받으면, 바로 연결을 끊어버리는 HTTP의 특성
Q) 페이지를 이동할 때마다 새로운 로그인을 계속 해줘야하는가?비상태성 (Stateless)
: 요청과 응답을 교환하는 동안 상태(state)를 저장하지 못하는 HTTP의 특성
따라서, HTTP 레벨에선 이전에 보냈던 요청과 응답을 기억하지 못한다.
Connectionless와 Stateless를 보완하기 위해 Cookie와 Session을 이용한다.
: 사용자의 인증 정보가 서버의 세션 저장소에 저장하는 방식
(1) Browser → App Server : Login 시도
(2) App Server → DB : 회원이 있는지 조회
(3) DB → App Server : 해당 Session ID 반환
Session Table
: 사용자 세션을 관리하기 위해 서버에서 사용하는 테이블
Session ID User ID abc123 23
(4) App Server → Browser : 해당 Session ID를 쿠키 값으로 응답
(5) Browser : 쿠키 값 저장
(1) Browser → App Server : 쿠키 값(Session ID) 전송
(2) App Server → DB : Session ID 조회
(3) DB → App Server : 조회 결과 해당 회원이 있다면, 요청 허용
(4) App Server → Browser : 요청 수행
: 인증 정보를 서버가 아닌 클라이언트가 직접 들고 있는 방식
암호화가 풀릴 가능성을 배제할 수 없다.
→ 토큰의 만료기간을 짧게 설정
payload 자체는 암호화되지 않고 base64로 인코딩된 데이터이므로, payload가 중간에 탈취되면 디코딩을 통해 데이터가 보여진다.
→ JWE를 통해 암호화하거나 payload에 중요한 정보를 넣지 않는다.
토큰을 탈취당할 경우, 유효기간이 지나기 전까지 조치를 취할 수 없다.
→ HttpOnly cookie에 토큰 저장, JWT 블랙리스트 관리(단, session 방식과 다를바 없음), 만료기간 짧게 설정(refresh token 운영 → refresh token 탈취를 막기 위한 resfresh token rotation 필요 혹은 refreash token은 1번만 사용되기 설정)
(1) Browser → App Server : 로그인 요청
(5) App Server → Browser : 생성된 JWT 전송
(6) Broswer : 쿠키나 로컬 스토리지와 같은 브라우저 저장 시스템에 JWT 저장
(1) Browser → App Server : 브라우저 저장 시스템에 저장된 JWT 전송
(2) App Server : 받은 JWT를 base64로 디코딩
(3) App Server → Browser : 인증된 사용자임으로, 브라우저가 원하는 요청 수행
: Json 형태로 된 데이터를 네트워크를 통해 서로 다른 장치끼리 안전하게 전송하기 위해 설계되었다.
: .(dot)을 구분자로 헤더, 내용, 서명을 구분하여 JWT 토큰 1개를 이룬다.

(1) HEADER
: 토큰을 어떻게 검증하는가에 대한 내용
{
"alg": "HS256",
"typ": "JWT"
}
(2) PAYLOAD
: 토큰에 담긴 사용자 정보 등의 데이터 저장, Claim으로 구성
Ex) 누가 누구에게 발급했는지, 유효기간 등
Q) 왜 Claim, 즉 주장이라고 명칭하는가?
- Payload를 받는 쪽과 보낸 쪽 모두에서 이 Claim을 곧대로 믿으면 안되기 때문에 주장이라고 명칭한다.
- 서명을 통해 이 내용이 믿을 수 있는 내용인지 즉, 내용의 무결성을 검증한다.
{
"sub": "123456",
"name": "John Doe",
"email": "John@example.com"
}
(3) SIGNATURE
: 서명. 부호화 시킨 header와 payload를 가지고 발급해준 서버가 지정한 secret key로 암호화 시켜 토큰 변조를 어렵게 한다.
[ 서명의 원리 ]
(1) 송신자 : Secret Key와 payload(내용)을 HMAC(서명 생성기)에 넣어, signature(서명)을 생성한다.
(2) 송신자 : header에 HMAC, payload, 생성된 signature을 base64로 인코딩하여(JWT) 수신자에게 전송한다.
(3) 수신자 : 수신 받은 JWT를 base64로 디코딩하여 payload 확인 가능.
차후, 인증이 필요할 때 JWT를 송신자에게 전송한다.
(4) 송신자 : 수신자에게 받은 JWT를 base64로 디코딩하여, Header의 적힌 알고리즘에 소유 중인 secret key와 디코딩된 payload를 대입하여 서명 생성
- 해당 서명이 디코딩된 서명과 동일한지 확인
- 동일하다면, 해당 payload는 이전 송신자가 생성한 것이 분명하게 된다.
: JWT는 탈취될 경우 위험성이 높다. 그렇다고 유효 기간을 짧게 두자니 사용자 입장에서 불편하다.
→ 유효기간이 다른 JWT 토큰 2개(Access Token, Refresh Token)을 통해 관리한다.
[ 탈취 위험 ]
: 하나의 서버와 여러 클라이언트 환경에서 모든 연결이 동시에 유의미한 통신을 하고 있을 확률이 적다. (= 서버의 자원 낭비) 따라서, HTTP 초기 모델은 클라이언트가 서버에 요청을 하고 응답을 받으면 바로 TCP/IP 연결을 끊도록 하는 방식 즉, Connectionless하게 운영하도록 하였다.
: HTTP 3 이전까지 HTTP는 TCP 기반으로 동작했다. OSI 7계층에 따르면, HTTP는 7계층에서, TCP는 4계층에 속해 있다.
- TCP의 연결 지향 : 클라이언트가 요청을 보내지 않더라도 계속 연결을 유지해야 한다.
→ 연결을 유지하는 서버의 자원이 계속 소모
- HTTP의 비연결성 : 실제로 요청을 주고 받을 때만 유지하고, 응답을 주고 나면 연결을 끊는다.
→ 최소한의 자원으로 서버 유지 가능
쉬운 이해를 위해, HTTP는 모니터, TCP는 HDMI 케이블이라고 비유해보자.
즉, TCP는 말 그대로 수단일 뿐, 이를 조작하는 것은 HTTP라고 보면 된다.
Access Token은 JS private Instance로 저장.
즉,const accessToken = xyz와 같이 frontend의 variable에 저장한다. = in-memory 저장
- 페이지를 새로 고침할 경우, access token은 사라지게 될 것이다. = refresh token이 필요한 이유
- access token이 사라지거나 만료시, cookie에 저장된 refresh token을
/refresh-tokenendpoint로 보내주어 새로운 access token을 발급받는다.
Refresh Token cookie setting :
(1)httpOnly(XSS 예방) 플래그 설정 : JS가 쿠키를 읽는 것을 방지
(2)secure = true: HTTPS에서만 요청을 보낼 수 있다.
(3)sameSite=strict(CSRF 예방) : Authorization Server가 사용자의 프론트엔드와 같은 사이트에서만 사용 할 수 있다.
- 만약 아닐 경우, Authorization server는 CORS header를 백엔드에서 설정하거나 refresh token 요청을 인증된 웹사이트에서만 완료시킬 수 있도록 세팅해야한다.
※ Local Storage는 XXS 공격에 취약하기에 적합하지 않다.
-> Javascript를 사용해 쉽게 접근할 수 있게 때문
※ 정확한 방식이 아닐 수 있다...
(1) 사이즈
- 세션의 경우 Cookie 헤더에 Session ID만 실어 보내면 되기에 트래픽을 적게 사용한다.
- JWT는 사용자 인증 정보와 토큰의 발급시각, 만료시각 등 담겨있는 정보가 Session ID보다 비대하기에 네트워크 트래픽을 훨씬 많이 사용한다.
(2) 안전성과 보안성
- 세션의 경우, 서버에서 관리하기에 보안 측면에서 더 유리하다. Session ID를 탈취당하더라도, 서버측에서 해당 세션을 무효 처리하면 된다.
또한, 모든 데이터가 서버에 저장되기에 아무나 함부로 열람할 수 없음으로 저장 데이터의 제한이 없다.- JWT는 서버가 트래킹하지 않고 클라이언트가 모든 인증 정보를 가진다. 따라서, 해커가 탈취하게 되면 만료될 때까지 피해를 입을 수 밖에 없다.
더욱이, payload는 별도로 암호화가 되어있지 않으므로 민감한 데이터를 실을 수 없다. 저장 데이터의 제한이 있다.
(3) 확장성 : 수평 확장을 근거로
- 세션 기반일 경우, 별도의 작업을 하지 않을 경우 수평 확장 시, 세션 불일치 문제가 발생한다. 이를 해결하기 위해선 Sticky Session, Session Clustering 등의 작업이 필요하다.
- 토큰 기반 인증 방식, 서버가 직접 인증 방식을 저장하지 않고, 클라이언트가 저장하는 방식이기 때문에 세션 불일치 문제에서 자유롭다.
이런 특징으로 HTTP의 비상태성을 그대로 활용할 수 있어 높은 확장성을 갖는다.
(4) 서버 부담
- 세션 기반은 모든 데이터를 서버가 관리하는 만큼 데이터 양이 많아질수록 부담이 커진다.
- 토큰 기반은 클라이언트가 인증 데이터를 직접가지기 때문에, 세션 기반에 비해 부담이 적다.
혹시 틀린 내용 있으면, 댓글 부탁드립니다!
Youtube [ 코딩 애플 : JWT 대충 쓰면 님들 코딩인생 끝남 ]