JWT 정리
Intro
로그인 서비스를 구현하게 된다면 세션방식, 쿠키방식, JWT방식 세 가지를 고려하게 됩니다.
이번에는 JWT방식을 활용하여 로그인 서비스를 구현을 하기 위한 필요한 개념들에 대해 정리를 해보았습니다.
또한 로그인 서비스를 구현하려하면 인증과 인가라는 개념에 대해서도 알고 있어야 하기에 먼저 정의를 해보았습니다.
인증과 인가
각각을 알아보기 이전에 인증과 인가를 되게 비슷하다고 생각을 할 수 있는데 둘은 엄연히 다른 개념이라는 걸 알아야합니다.
둘은 사용자의 정보를 효율적으로 식별하고 전달하는 과정에서 필수적인 일들입니다.
인증
인증은 쉽게 말하면, 로그인입니다.
클라이언트가 주장하는 신원을 확인하는 과정으로 다음과 같은 인증방식이 있습니다.
- 사용자 ID 및 비밀번호
- OAuth
- SAML
- API Key
- Token
위 정보를 바탕으로 클라이언트로부터 시스템(서버)에 접근하는 사용자의 신원을 확인하는 일련의 과정입니다.
인가
인가는 해당 클라이언트가 인증이 되었다는 가정하에 진행되는 절차입니다.
인증된 사용자가 어떠한 리소스에 접근할 수 있는지 권한여부 등을 결정하는 과정입니다.
예를 들어, USER1은 USER2의 비밀번호를 변경할 수 없도록 설계가 되야합니다. 이를 인가라는 작업과정을 배치함으로써 해당 클라이언트의 할 수 있는 작업들에 대한 판별을 할 수 있게됩니다.
정리를 해보자면,
인증과 인가의 차이점 다음과 같습니다.
인증 : 누구인지 확인
인가 : 무엇을 할 수 있는지 확인
인증과 인가 절차를 두어야 하는 이유는 다음과 같습니다.
- 시스템 보안 유지
- 권한 관리
- 사용자 맞춤화 경험 제공
JWT 인증 과정
로그인
- 사용자는 로그인 시 사용자 ID와 비밀번호를 서버에 전송합니다.
- 서버는 사용자 정보를 검증하고 유효하면 JWT 토큰을 생성합니다.
- 토큰에는 사용자 ID, 권한, 만료 시간 등의 다양한 정보가 포함될 수 있습니다.
- 서버는 토큰을 사용자에게 응답을 전송합니다.
요청
- 사용자는 클라이언트(웹 브라우저, 모바일 등)에서 API를 요청할 때 JWT토큰을 헤더에 포함하여 전송합니다.
- 서버는 토큰을 받아 서명 검증을 수행합니다.
- 서명 검증이 성공하면 토큰에 포함된 정보를 사용하여 사용자를 식별하고 권한을 확인합니다.
- 서버는 요청에 대한 응답을 전송합니다.
CASE : 토큰 만료
- JWT토큰에는 만료 시간이 설정되어 있습니다.
- 토큰이 만료되면 사용자는 다시 로그인해야 합니다.
- 서버는 만료된 토큰을 거부하고 사용자에게 새로운 토큰을 발급하도록 요청합니다.
이를 그림으로 나타내면 다음과 같습니다.
위 과정은 Refresh Token + Access Token을 활용하였을 때의 흐름이며, 만약 Refresh Token없이 Access Token만 사용한다면 클라이언트는 만료 응답을 받고 재로그인을 수행하여야 합니다.
서버에서는 클라이언트로받는 JWT토큰에 대한 유효성 검증을 다음과 같이 진행합니다.
헤더 검증
- 서버는 토큰의 헤더 부분을 base64로 디코딩하여 JSON 객체로 변환합니다.
- 변환된 JSON 객체에서 알고리즘 및 토큰 종류를 확인합니다. (예 : SHA256, JWT)
- 알고리즘은 서버에 지정된 알고리즘과 일치해야 합니다.
시그니처 검증
- 서버는 토큰의 시그니처 부분을 base64로 디코딩하여 바이트 배열로 변환합니다.
- 헤더에서 확인한 알고리즘을 사용하여 서버의 비밀 키와 페이로드를 기반으로 새로운 서명을 생성합니다.
- 생성된 새로운 서명과 클라이언트에게 받은 토큰의 서명을 비교합니다.
- 두 시그니처가 일치해야 유효성 검증이 이루어집니다.
페이로드 검증
- 서버는 토큰의 페이로드 부분을 base64로 디코딩하여 JSON객체로 변환합니다.
- 변환된 JSON 객체에서 발급 시간, 만료 시간, 사용자 정보 등을 확인합니다.
- 만료 시간이 현재 시간보다 이전이면 토큰이 만료된 것으로 간주됩니다.
- 사용자 정보는 서버에 저장된 사용자 정보와 일치해야 합니다.
JWT토큰을 활용한 사용자 인증방식에서 주의해야할 점이 있습니다.
해당 방식의 목적을 한번 생각해보면 좋을 것 같은데, 정보 보호의 목적이 아닌 위조를 하지 못하도록 방지하는 것을 목적으로 하기 때문에 페이로드 부분은 언제든지 탈취당할 가능성이 존재합니다.
그러므로 페이로드에는 중요한 정보를 넣지 말아야합니다. 만약 중요한 정보를 토큰으로 관리하고 싶다면 API로 분리시켜놓는 것이 좋을 것 같습니다.
추가로 페이로드에 담는 정보가 늘어날수록 토큰의 길이가 커져 네트워크 부하가 커질 염려가 있습니다.
위에서 알아본 가장 단순한 JWT 인증 방식에서는 Access Token 그 자체를 누군가에게 탈취당했을 경우 발생하는 문제점이 있습니다.
예를 들어 Token을 변조 하는 것이 아닌 해당 Token에 담긴 권한 자체를 이용하는 공격에 대해서는 막을 수 있는 방법이 없습니다.
또한 Token은 브라우저 단에서 저장을 하고 사용을 하고 있기 때문에 서버 입장에서 해당 Token이 탈취되었는지, 탈취되었다면 삭제시킬 방법이 없기에 탈취에 매우 취약합니다.
이러한 점을 보완하기 위해 Token의 만료 시간을 매우 짧게 하여 자주 발급받도록 할 경우 사용자는 매번 로그인을 다시 해야하기 때문에 UX적으로 불편함을 줄 수 있습니다.
이러한 점들을 해결하기 위해 Access Token을 비롯하여 Refresh Token까지 2개의 토큰으로 나누어 인증을 하는 방식을 택할 수 있습니다.
두 토큰 모두 같은 종류의 토큰이지만 차이점이 있습니다.
- 토큰 저장 위치
- 만료 시간
Refresh Token?
Access Token은 실질적인 API 사용을 위한 토큰으로써 해당 토큰을 사용하여 인가처리를 진행합니다.
반면 Refresh Token은 Access Token의 만료 시간이 다 될 경우 재발급을 위한 토큰으로 사용됩니다.
최초 로그인의 경우 서버는 사용자 인증을 처리하고 유효할 경우 Access Token, Refresh Token 두 가지의 토큰을 발급합니다.
Refresh Token의 경우 데이터베이스에 저장을 합니다.
만료 시간의 설정같은 경우 아래와 같으며 기업마다, 개발자마다 다르게 설정하므로 참조하시면 될 것 같습니다.
- 액세스 토큰 : 1시간 ~ 1개월
- 리프레시 토큰 : 2주 ~ 2년
재발급 원리
기간이 만료된 Access Token을 서버로 보낼 경우, 서버는 같이 보내진 Refresh Token을 DB에 저장된 값과 비교하여 일치할 경우 다시 Access Token을 재발급하는 간단한 방식입니다.
만일 사용자가 로그아웃할 경우 DB의 Refresh Token을 삭제하여 재사용이 불가능하도록 처리합니다.
'Develop > SpringBoot' 카테고리의 다른 글
[Springboot] 액추에이터(Actuator) (1) | 2024.04.16 |
---|---|
[JPA] 인스타그램 유저 검색 N+1 문제 (0) | 2024.04.02 |
[JWT] JSON Web Token - With JWT.io (0) | 2024.03.11 |
세션(Session) & 쿠키(Cookie) (0) | 2024.02.23 |
[Swagger] 스프링 3.x Swagger 적용(With. SpringDocs) (1) | 2024.01.31 |
개발 기술 블로그, Dev
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!