본문 바로가기
WEB

JWT

by jinukix 2021. 10. 4.

토큰 기반 인증 시스템

기존의 인증 시스템에서는 서버 측에서 유저들의 정보를 관리했습니다. 하지만 서비스의 규모가 커짐에 따라 서버 기반 인증 방식의 문제가 보이기 시작했습니다. 이로 인해 현대 웹 서비스에서는 인증받은 사용자들에게 토큰을 발급하고, 서버에 요청을 할 때 헤더에 토큰을 함께 보내도록 하여 유효성 검사를 하는 토큰 기반 인증 시스템이 나오게 되었습니다.

 

세션 기반 인증 시스템의 가장 큰 단점으로는 다수의 서버 환경에서 사용 시 문제가 발생하기 쉽다는 점입니다. 모든 서버들이 같은 세션 스토리지를 공유하고 있어야 하기 때문입니다. 토큰 기반 인증 시스템은 이러한 점을 보완할 수 있습니다.

 

토큰 기반 인증 시스템의 주요한 이점은 사용자 인증에 필요한 모든 정보를 토큰 자체에 포함하고 있기 때문에 별도의 인증 저장소가 필요 없다는 것입니다. 토큰이 올바르게 서명되었는지 확인하는 것은 CPU 사이클을 필요로 하며 IO, 네트워크 액세스가 필요하지 않습니다.

JWT (Json Web Token)

JWT란 Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Web Token으로 현재 토큰 기반 인증 시스템에서 주로 사용하는 토큰입니다. JWT는 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달합니다.

JWT 구조

jwt.io

https://jwt.io 에서 암호화된 토큰을 확인할 수 있습니다.

 

JWT는 Header, Payload, Signature의 3 부분으로 이루어집니다. Json 형태인 각 부분은 Base64로 인코딩 되어 표현됩니다. 또한 각각의 부분을 이어 주기 위해 구분자로 . 을 사용합니다.

 

  • Header: 위 3가지 정보를 암호화할 방식(alg), 타입(typ)등이 들어갑니다.
  • Payload: 서버에 보낼 데이터가 들어갑니다. 일반적으로 유저의 고유 ID값, 유효기간이 들어갑니다.
  • Signature: Base64 방식으로 인코딩된 Header, Payload 그리고 SECRET KEY를 더한 후 서명됩니다.

최종적인 결과는 다음과 같은 형태가 됩니다.

Encoded Header + "." + Encoded Payload + "." Verify Signature

Header, Payload는 인코딩될 뿐(16진수) 따로 암호화되지 않습니다. 따라서 JWT 토큰에서 Header, Payload는 누구나 디코딩하여 확인할 수 있습니다. 

 

하지만 Verify Signature는 SECRET KEY를 알지 못하면 복호화할 수 없습니다.

 

생성한 토큰은 보통 HTTP 통신을 할 때 Authorization이라는 key의 value로 사용됩니다. 일반적으로 value에는 Bearer이 앞에 붙여집니다.

{ 
	"Authorization": "Bearer {생성된 토큰 값}"
}

JWT는 다음과 같이 사용됩니다.

1. 사용자가 아이디와 비밀번호로 로그인을 합니다.

2. 서버에서 계정정보를 읽어 사용자의 고유한 ID값을 부여한 뒤, 기타 정보와 함께 Payload에 넣습니다.

3. JWT의 유효기간을 설정합니다.

4. 암호화할 SECRET KEY를 이용해 ACCESS TOKEN을 발급합니다.

5. 사용자는 토큰을 받아 저장한 후 인증이 필요한 요청마다 토큰을 헤더에 실어 보냅니다.

6. 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후 조작 여부, 유효 기간을 확인합니다.

7. 검증이 완료되면 Payload를 디코딩하여 사용자에 ID에 맞는 데이터를 가지고 옵니다.

 

세션/쿠키 방식과 가장 큰 차이점은 세션/쿠키는 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보를 넣는다는 점입니다. 물론 클라이언트 입장에서는 HTTP 헤더에 세션 ID나 토큰을 실어서 보낸다는 점은 동일하나 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하는 차이가 발생하게 됩니다.

JWT의 장점

사용자의 정보를 서버에서 저장하지 않으므로 Stateless 한 서버를 만들 수 있습니다. 이는 서버를 확장하거나 유지 보수하는데 유리합니다. 그리고 확장성이 뛰어납니다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능합니다. 예를 들어 소셜 로그인 기능은 모두 토큰을 기반으로 인증을 합니다.

JWT의 단점

이미 발급된 JWT에 대해서 핸들링을 할 수 없습니다. 세션/쿠키의 경우 쿠키가 악의적으로 이용된다면 해당하는 세션을 지워버리면 되지만 JWT는 한 번 발급되면 유효기간이 발급될 때 까지는 계속 사용이 가능합니다.

-> 이러한 단점은 유효기간을 짧게 하고 Refresh Token이라는 새로운 토큰으로 어느정도 보완할 수 있습니다.

 

Payload는 따로 암호화 되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있습니다. 유저의 중요한 정보들은 Payload에 넣을 수 없습니다. 세션/쿠키 방식에 비해 JWT의 길이가 길어 인증이 필요한 요청이 많아질수록 서버의 자원낭비가 발생할 수 있습니다.

Refresh Token

Access Token(JWT)를 통한 인증 방식의 문제는 만일 제삼자에게 탈취당할 경우 보안에 취약하다는 점입니다.

유효기간이 짧은 토큰의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 토큰을 발급받아야 하므로 불편합니다.

그러나 유효기간을 늘리자면 토큰을 탈취당했을 때 보안에 더 취약해지게 됩니다.

 

Refresh Token은 Access Token과 똑같은 형태의 JWT입니다. 처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서, Access Token이 만료되었을 때 새로 발급해주는 열쇠가 됩니다.

 

사용 예시를 들어보자면 Refresh Token의 유효기간이 2주, Access Token의 유효기간이 1시간이라고 할 때, 사용자는 API를 사용하다가 1시간이 지나게 되면 Access Token은 만료됩니다. 그러면 Refresh Token의 유효기간 전까지는 Access Token을 새롭게 발급받을 수 있습니다.

 

Access Token이 탈취당했을 때 정보가 유출되는 것은 동일하나, 다만 짧은 유효기간 안에만 사용이 가능하기에 더 안전하다는 의미입니다. Refresh Token의 유효기간이 만료되었다면 사용자는 새로 로그인해야 합니다.

Access Token + Refresh Token 인증 과정

1. 사용자가 아이디와 비밀번호로 로그인을 합니다.

2. Access Token, Refresh Token을 발급합니다. 이때 일반적으로 회원 DB에 Refresh Token을 저장합니다.

3. 사용자는 Refresh Token을 안전한 저장소에 저장 후, Access Token을 헤더에 실어 요청을 보냅니다.

4. 시간이 지나 Access Token 만료되었다고 가정하겠습니다.

5. 사용자는 Refresh Token과 Access Token을 함께 서버로 보냅니다.

6. 서버는 Access Token이 조작되지 않았는지 확인한 후, Refresh Token과 DB에 저장되어있던 Refresh Token을 비교합니다. 

Refresh Token이 유효기간이 지나지 않았다면 새로운 Access Token을 발급해 줍니다.

 

이로써 Access Token만을 사용했을 때보다 안전하게 사용할 수 있습니다.

하지만 구현이 복잡해졌고, Access Token이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청 횟수가 많아졌습니다.

댓글