JWT 개념과 탈취 대안까지의 핵심 정리
이 포스팅은 Cookie, Session, Token을 안다는 가정 하에 진행됩니다.
대부분의 사용자 인증/인가 작업에 JWT를 알아보고 탈취 위험과 이를 방지하기 위한 기법까지 알아보겠습니다.
JWT(Json Web Tokens)
- 서버에서 상태를 저장하는
Session
방식의 몇가지 한계를 극복하기 위해stateless
방식으로 개발되었다.세션 방식은 서버의 자원을 많이 사용하고, 서버 확장성에 제약이 있다는 한계가 있다.
- 토큰 형식이다.
모바일 환경에서 쿠키처럼 사용하기 위해
Token
이라는 개념이 도입됐다. - 랜덤한 문자열을 갖는 토큰과 달리 형식이 정해져 JWT 안에 여러 정보들을 넣을 수 있다.
JWT의 구조
- Header, Payload, Signature 3가지 구조로 이루어져 있다.
- Header, Payload 는 안전하게 전송할 수 있도록
Base64
로 인코딩된다.이 인코딩은 암호화가 아니고, 쉽게 디코딩 가능하다.
- Signature는 인코딩한 Header, Payload 와 서버에서 보관하는 비밀 키를 사용하여 암호화한다.
[JWT access/refresh 예시]
[Header]
- 주로 typ, alg 두가지 정보를 담고 있다.
- typ (Type)
- 토큰의 타입을 명시한다.
- 일반적으로 JWT 라고 표시된다.
1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}
[Payload]
- 서비스에 필요한 정보들을 담는다.
- 쉽게 디코딩되므로 절대 민감한 정보를 담아서는 안된다.
1
2
3
4
5
6
7
{
"category": "access",
"username": "admin",
"role": "ROLE_ADMIN",
"iat": 1714888832,
"exp": 1714889432
}
[Signature]
- 헤더의
alg
정보에 있는 알고리즘으로 암호화된다. - 알고리즘의 인자로는 인코딩된 Header, Payload와 비밀키가 사용된다.
이때 사용되는 비밀키는 서버만 알고, 서버만 가지고 있다.
- 서버의 유효 토큰 확인
- 서버는 Signature를 비밀키로 해독하여 암호화에 사용된 Header, Payload 정보를 얻는다.
- 해독으로 얻은 정보들과 받은 정보들을 비교하여 토큰이 조작되었는지 여부를 확인할 수 있다.
Digital Signature
- 서버는 토큰이 조작되지 않음을 확인함으로써 올바른 사용자임을 확인한다.
- 이후 payload의 정보들을 통해 토큰이 올바른지, 만료되지 않았는지 추가로 확인한다.
탈취 위험
- 네트워크 통신에서 오가는 jwt 토큰을 완벽히 숨길 수는 없기 때문에 결국 탈취 위험이 존재한다.
- 탈취자가 토큰을 가지고 특정 사용자인척 서비스를 사용하면 진짜 사용자는 피해를 입게 될 수 있다.
- 이를 완벽하게 차단할 방법은 없지만 피해를 최소화하기 위해 단일 토큰이 아닌
access/refresh
다중 토큰을 주로 사용한다.
access/refresh 다중 토큰
네트워크 상에 노출될수록 토큰이 탈취당할 위험이 높다
를 전제로 토큰을 나누었다.- 사용자가 로그인할 때 서버는 access 토큰과 refresh 토큰을 발급해준다.
[access 토큰]
- 인증/인가에 사용되는 토큰이다.
- 사용자는 매 요청마다 access 토큰을 헤더에 담아 요청한다.
- 자주 전달되어 탈취당할 위험이 높으므로, 탈취당하더라도 그 피해를 최소화하기 위해 유효기간을 짧게 설정한다.(약 10분)
- access 토큰이 만료되면 refresh 토큰을 통해 새로 발급받는다.
[refresh 토큰]
- 오직 access 토큰을 발급하는 데에만 사용한다.
access 토큰보다 덜 전달되어 탈취당할 위험이 상대적으로 적으므로 유효기간을 길게 설정한다.(24시간 이상)
- 그러나, 상대적으로 탈취 위험이 적은 것일뿐, 0%는 아니다.
- 탈취 당했을 때의 피해를 줄이고자,
Refresh Token Rotation(RTR)
기법이 사용된다.
Refresh Token Rotation
- refresh 토큰을 일회용으로 설정하여 사용자가 refresh 요청을 할 때마다 access 토큰 뿐만 아니라, refresh 토큰도 새로 발급해준다.
- 이전 refresh 토큰은 만료처리한다.
- 만약 만료된 refresh 토큰으로 요청이 온다면 해당 사용자의 모든 refresh token을 무효화시킨다.
- 사용자는 재로그인 해야만 서비스를 다시 이용할 수 있다.
- 탈취자는 유효한 refresh 토큰을 다시 탈취하지 않는 이상, 서비스를 다시는 이용할 수 없다.
[탈취 시나리오]
Malicous Client : 공격자, Legitimate Client : 사용자
RT : refresh token, AT : access token
- 공격자가 RT(1)을 탈취한다.
- 공격자가 RT(1)으로 AT를 요청한다.
- AT(2)와 RT(2)가 공격자에게 반환된다.
- RT(1)가 무효화되고, 사용자가 RT(1)으로 AT를 요청한다.
- 재사용이 감지되어 RT Family가 무효화 된다. 서버는 사용자에게 Access Denied 응답한다.
- 공격자가 RT(2)로 AT를 요청한다.
- 모든 RT가 무효화되었으므로 서버는 Access Denied를 응답한다.
출처
누군가가 물어본다면
JWT는 기존 세션 방식의 성능, 확장성 문제를 해결하기 위해 stateless
구조로 설계되었습니다.
하지만 탈취 위험은 여전히 존재했고 이 피해를 최소화하기 위한 Refresh Token Rotation
등의 기법이 사용되고 있습니다.
This post is licensed under CC BY 4.0 by the author.