본문 바로가기

백엔드 개발/Spring-Security

JWT에 대하여

1. JWT란 무엇인가?

기본적인 토큰 인증 방식을 따르고, 거기서 토큰 자체를 강화한 방식이라 생각하면 된다.
원래의 토큰 인증 기반에서 요청자가 보내온 ID/PW 가 DB에 존재하면 (우리 회원이 맞으면) 그 요청자에게 자신들의 API를 쓸 수 있는 허가증인 토큰을 전해줬었다.

image-20240313213753190

 

image-20240313213805761

여기서 더해 JWT의 경우 토큰을 만들 때, 사용자의 정보(간단한 개인정보 등 +@)를 암호화하여 만든다.

이렇게 되면 무엇이 좋을까?
아까 토큰 자체가 사용자에 대한 개인 정보라고 하였다. 회원가입을 하여 토큰을 받았다면, 이후 API 요청을 할 때, 토큰을 Header나 Cookie에 넣어서 보낸다. 만약 클라이언트가 원하는 요청이 사용자의 개인정보에 대한 요청이라면, 서버에서는 DB를 조회할 필요없이 토큰을 복호화 하여 그 안의 값을 다시 보내줘도 된다. 이는 속도를 빠르게 해준다. 이외에도 많은 장점이 있으므로 후술 하겠다.

2. JWT의 구조

image-20240313215406199

  • Header
    header부분에는 JWT의 타입과,
    JWT 토큰 위변조 방지를 위한 전자 서명 만들 때, 사용된 해시 알고리즘이 무엇인지 적혀있다.
  • Payload
    아까 1번에서 말했던 사용자에 대한 간단한 개인정보가 들어있다. 해당 정보들이 BASE64-URL-safe Encode를 통해 암호화된 상태이다. 그 내용을 복호화 하면 위와 같은 JSON 형태로 바꿀 수 있다.
  • Signiture
  • 인코딩된 header, 인코딩된 payload, server가 가지고 있는 secret-key를 Header에 표기된 해쉬 알고리즘에 넣어서 나온 값이다. 우리는 이 값을 통해 요청으로 들어온 JWT가 위변조 되었는지 아닌지를 체크할 수 있다. (어떻게 위변조 체크를 하는지는 뒤에서 알아보자.)

3. JWT를 이용한 토큰 인증 방식의 과정

image-20240313221626069

기존 토큰 인증 방식과 큰 틀은 똑같다.

  1. 클라이언트가 요청을 보내고, 진짜 우리 회원인지 확인한다.
  2. 우리 회원이 맞으면 토큰을 보낸다.

다만 이 때 보내는 토큰이 Access Token(이하 AT), Refresh Token(이하 RT)로 두 개이다. AT는 우리가 쓰던 그대로 Server에 API 요청을 하기 위해 쓰인다. RT는 언제 쓰일까?
토큰 인증 방식의 취약점으로 항상 대두되었던 것이, 중간에 AT를 탈취 당하면 아무 상관없는 제 3자도 원 주인의 개인정보에 기반한 API를 가져올 수 있다는 것이었다. 거기에 대한 보완점으로 JWT가 내놓은 대답은 AT 자체에 수명을 짧게 두는 것이다. 이렇게 된다면 누가 AT를 탈취하여도 금방 만료되어 쓰지 못하게 된다.
그러면 우리의 선량한 사용자도 AT 수명이 다 할때마다 원래의 로그인 절차를 다시 밟아야 하는가? 현재 많은 서비스의 AT 수명은 한 시간인데, 이렇다면 우리는 코테 문제를 풀다가 한 시간이 지나버렸을 경우, 제출버튼을 눌렀는데, 로그인 창으로 가버려서 코딩 내역을 다 날려버릴 것이다!
이러한 짧은 AT 수명에 대한 보안점으로 RT가 등장하였다.RT 또한 JWT 토큰인데, 오직 AT를 재발급 하는 용도로만 쓴다. RT의 경우 사용자 정보와 같이 DB에 저장하는 경우가 많다. 따라서 사용자가 RT를 통해 재발급 요청을 하면, Server는 해당 사용자 레코드에 적힌 RT와 대조하여 일치하면 AT를 다시 제공해준다. 이렇게 RT는 AT가 만료된 경우에만 요청에 등장하기 때문에 간헐적이라 탈취가 쉽지 않을 것이다. RT의 평균 수명은 한달 ~ 두달 정도로 넉넉하다.

image-20240313221640737

4. JWT 토큰 인증 방식이 신뢰성을 가지는 이유

JWT 토큰 인증 방식이 신뢰성을 가지는 이유는 JWT 토큰의 위변조 여부를 Server에서 가려낼 수 있기 때문이다. 어떻게 가려낼까? JWT 토큰의 경우 크게 3가지 부분으로 나눌 수 있었다.
A (인코딩된 Header) + B (인코딩된 Payload) + C(전자서명)
C의 전자서명은 (해당 A, B + server에 존재하는 Secret Key)를 해쉬 알고리즘으로 암호화 했을 때의 반환값이었다.

Server에서 C를 재현할 수 있을까?

있다. server에 요청이 들어왔다면 헤더에 JWT(A+B+C) 도 들어왔다는 것이기 때문에 C를 만들 수 있는 매개 변수가 모두 존재한다.
ex) HSA256(A,B,server-key) = C

만약, 나쁜 마음을 먹은 누군가가 JWT를 탈취해서 A나 B중 정보를 위변조 했다고 치자, JWT 인증 절차를 거치지 않고 위변조된 토큰이 그대로 Server에서 쓰인다면, DB를 헤집어서 난장판으로 만들 가능성이 있다. (회원 정보에 잘못된 값 insert 등) 따라서 위험하다. 이러한 위변조를 방지하기 위해 JWT 구조 중 C(전자서명) part가 쓰인다.

누군가 payload를 위조해서 JWT를 다음과 같이 만들었다고 하자. Payload B를 위조한 새로운 Payload를 B'라고 하면,

JWT2(A+B'+C)

이걸로 전자서명을 재현하려고 들면, HSA256(A,B',Server-key)로 들어가게 되고, 인수가 달라지니, 반환값도 원래의 JWT와 완전히 달라질 것이다.

ex) HSA256(A,B',server-key) = %%)@$(#(

 

이는 JWT의 C part와 다른 값이다. 이렇게, 들어온 JWT 값을 이용하여 C를 재현하려 했을 때, 재현이 되지 않는다면, 해당 JWT는 위변조 된 것으로 판단할 수 있다.

 

이런 식으로 JWT는 위변조에 강하기에, JWT 토큰 인증 방식은 일반 토큰 인증방식보다 신뢰성을 가진다.

'백엔드 개발 > Spring-Security' 카테고리의 다른 글

특화 프로젝트 Spring Security 분석  (0) 2024.04.26
[01]-OAuth2 이론  (0) 2024.03.03