서버가 유저 A, B를 구분하는 방법에는 무엇이 있을까?
서비스 진입 맨 처음 ID/PW 를 입력한다. 이는 유저를 식별할 수 있는 핵심 데이터이다. 하지만, 매번 페이지를 이동할 때마다 로그인을 유도할 수 없다. 이때 필요한 것은 로그인을 대체할 '인증 수단' 이다. 그 중 하나가 바로 JWT (Json Web Token) 이다.
JWT 인증 플로우 (심플)
JWT 토큰 인증 플로우는 다음과 같다. 로그인에 성공하면 서버는 AccessToken 을 발급하고 앞으로 이를 토대로 유저를 식별한다. 클라는 Token 정보를 저장하고 있다가 인가가 필요한 요청 헤더 혹은 쿠키에 설정 후* 정상 플로우를 탈 수 있다.
* 헤더 혹은 쿠키에 설정하는 기준은 추가 공부 필요
여기서 의문이 들 수 있다.
- 어떻게 유저를 식별할 수 있지? JWT는 단순 Random String 아닌가?
- Token 을 탈취해서 바꿔버릴 수 있을 것 같은데 보안에 취약하지 않다는 근거는 무엇일까?
- 유저의 로그인 상태를 계속 유지하는게 맞을까? 만약 중간에 로그아웃하거나 일주일 뒤에 방문하면?
위 의문점을 해소해보자.
JWT 구조
우선 JWT 구조를 살펴보자. 다음은 https://jwt.io/ 사이트에서 생성한 JWT 예시이다.
온점을 기준으로 3부분으로 나뉘어져있고 Header / Payload / Signature 의미를 갖고 있다.
- Header : Algorithm & Token Type
- Payload : Data
- Signature : Secret Key를 토대로 위변조 방지
이때 Header, Payload는 단순히 Encoding 된 값이기 때문에, Decoding이 쉽다. 그래서 프론트 개발할 때 필요한 유저 정보들을 (userId, userName 등 탈취되어도 괜찮은 정보로) 담아놓아 jwt-decode 라이브러리로 쉽게 파싱해서 사용한다. 그리고 Signature 부분은 SecretKey가 유출되지 않는한, 복호화할 수 없기 때문에 서버가 해당 토큰이 유효한지 판단하기 위한 추가 정보이다.
그렇게 우리는 첫번째, 두번째 의문점을 풀 수 있었다.
Q. 어떻게 유저를 식별할 수 있지? JWT는 단순 Random String가 아닌가?
Q. Token 을 탈취해서 바꿔버릴 수 있을 것 같은데 보안에 취약하지 않다는 근거는 무엇일까?
A. JWT는 json 형태로 paylod에 유저 식별 정보를 담고 있다. 이때 서버만 알 수 있는 SecretKey로 클라에서 넘겨받은 토큰 값을 한번 더 검증하고 인가된 응답을 내릴 수 있다.
하지만, 액세스 토큰 자체가 탈취될 경우 여전히 보안상 위험이 도사리고 있다. 이를 위해 인증 유효 기간을 적절하게 짧게 가져가는 것이 중요하다. 인증 유효 기간은 어떻게 관리될까? 이때 필요한 개념이 바로 만료 일자, RefreshToken 이다.
Refresh Token을 이용한 만료된 토큰 갱신하기
아까 플로우로 돌아가보자. 유저 인증 후 AccessToken 그리고 'RefreshToken' 이 추가적으로 발급된 것을 확인할 수 있다. 그리고 AccessToken 이 만료된 시점에, RefreshToken을 이용해 AccessToken을 재발급 받고, 다시 정상 플로우를 타면된다.
그럼 만료된 시점은 어떻게 판단할까?
- 클라측에서는 payload에 담겨있는 expireTime을 미리 확인해서, 사전에 갱신해줄 수 있을 것 같고
서버측에서는 인가가 필요한 요청에 담긴 토큰이 만료되었음을 에러로 내려주면, 클라측에서 이를 intercepter 로 잡아서 갱신 후 정상 플로우를 타게하는 방법이 있을 것 같다.
- 또한 서비스 특성에 따라 만료 시점을 달리 둘 수도 있다. (예로 금융 서비스는 더 빨리 만료되도록, 웹뷰에서는 좀 더 길게)
JWT 인증방식 장단점
- 대개는 Session 방식과 비교하며 '따로 세션 관리 저장소가 필요 없어서 서버 확장에 용이하다' 가 있다. 그 말은 즉, 규모가 작은 프로젝트에서는 세션 방식으로 서버측에서 로그인 상태를 관리하는 장점을 취할 수도 있다는 것이다. 상황에 맞는 선택이 필요할 것 같다.
- 또한 클라측에서 토큰을 관리하다 보니 보안상 완벽하지 않고, 추가적으로 설정할게 많을 수 있다.
참고자료
- https://blog.bizspring.co.kr/%ED%85%8C%ED%81%AC/jwt-json-web-token-%EA%B5%AC%EC%A1%B0-%EC%82%AC%EC%9A%A9/?ckattempt=1
- https://velog.io/@cocowonji/Next-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84
- https://velog.io/@chickenrun/%EC%84%B8%EC%85%98-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-VS-Token-%EC%9D%B8%EC%A6%9D%EB%B0%A9%EC%8B%9D%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%9D%B8%EA%B0%80
- https://velog.io/@from_numpy/NestJS-How-to-implement-Refresh-Token-with-JWT
'1️⃣ 개발 지식 A+ > FE' 카테고리의 다른 글
Next.js 13.4+ App Router 도입 고민 (feat. styled-component) (0) | 2025.01.10 |
---|---|
브라우저 캐시 (0) | 2025.01.07 |
브라우저 렌더링에서 메인 쓰레드 역할 (0) | 2024.12.23 |
Web 3D rendering (0) | 2023.09.28 |
[JS] 비동기 동작 스케줄링 방법 3가지 (0) | 2020.12.22 |