쿼카러버의 기술 블로그
[JWT] JWT란 무엇인가? (JSON Web Token) 쉽게 정리한 core개념들 본문
JWT는 개발자라면 지겨울정도로 들어봤거나 사용해볼법한 인증 방식이다.
필자도 마찬가지로 JWT를 많이 사용해 봤지만 구체적인 개념들에 대한 정리가 안돼있었다.
그래서 본 글에서 간단하게 정리해보려고 한다.
자 그럼 시작해보자~
JWT란?
JWT는 사용자 인증을 위해 사용하는 open standard(RFC 7519)다. Json포맷을 이용하여 Self-Contained 방식으로 사용자에 대한 정보를 저장하는 Claim기반 Web 토큰이다.
기본적인 컨셉은 IdP
(Identiy Provider)가 사용자의 정보를 담은 내용에 서명함을 통해서 토큰을 만들고, 유저가 서버에 요청할 때 사용하도록 하는데, 이 때 토큰의 integrity와 authenticity를 보장한다는 점이다. 쉽게 말해서 유저가 전송하는 데이터를 숨기는 것보다는, 유저가 전송하는 데이터를 인증하는데 집중한다.
특징
- JWT는 token based stateless authentication 메커니즘이다. 서버에서 해당 토큰정보를 저장할 필요가 없기 때문이다.
- Session 토큰의 단점 (분산화된 시스템에서의 세션 관리 문제 등)을 보완하기 위해 탄생했다.
JWT의 구조
JWT는 세 파트로 나누어지고, 각 파트는 .으로 구분하여 aaaaa.bbbbb.ccccc
로 표현된다. 또한 URL에서 파라미터로 사용할 수 있도록 하기 위해 url_safe한 base64 인코딩을 사용한다. 차례대로 구성요소들을 살펴보자.
1. Header
토큰의 타입(기본값으로는 JWT)과 JWT를 서명하는데 사용한 알고리즘을 명시한다. 대표적으로 사용되는 알고리즘에는 HMAC, SHA256, RSA, HS256 or RS256가 있다.
{
"typ": "JWT",
"alg": "HS256"
}
2. Payload
유저의 정보를 의미한다. 여기에 담은 정보의 한 조각을 Claim이라고 브르고, name/value의 한 쌍으로 이루어져 있다. 대표적으로 사용되는 claim은 아래와 같다
- Issuer(iss)
- Subject (sub)
- Audience (aud)
- Expiration time (exp)
- Issued at (iat)
{
"sub": "user10001",
"iat": 1569302116
}
위 claim외에도 custom claim들도 사용될 수 있다. 하지만 다음을 주의해야 한다.
- 큰 용량의 데이터를 사용하지 말자. Claim set은 최대한 가벼울수록 좋다.
- Sensitive한 정보를 담지 말자. JWT는 쉽게 decode되기 때문이다.
3. Signature
서명은 JWT의 가장 핵심적인 파트다. 서버에서 토큰의 정보가 서버로부터 생성된 것인지 증명하기 위해 사용한다. 서명을 하기 위해서는 base64 encoded 헤더와 payload를 .(period) seperator로 concatenate 후 헤더에 명시된 알고리즘으로 private key를 사용해 서명한다. 해쉬 알고리즘을 사용했기 때문에, header나 payload변경시 서명이 무효화된다.
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
signature = HMAC-SHA256( data, secret_salt )
IdP(Identity Provider)에서만 private key를 가지고 있기 때문에, 토큰 정보의 조작을 방지할 수 있다.
3-1. HS256 알고리즘
HS256알고리즘(HMAC = keyed-hash message)은 Symmetric key encryption알고리즘으로, 하나의 secret key를 사용해 데이터를 서명하고, 검증한다. HS256을 사용하는 경우에는 JWT의 서명 부분과 유저가 보낸 JWT의 header.payload부분을 똑같은 secret key로 서명후 같은지 비교하는 방식으로 토큰을 검증한다.
이 방식의 단점은, 분산화된 시스템에서 secret key를 계속 공유해야 한다는 점이다. 서명하는 주체 뿐 아니라, 검증하는 주체에서도 secret key를 필요로 하기 때문이다. 이를 해결하기 위해 단일의 token의 생성과 검증만을 담당하는 서비스를 새로 만들 수 있지만, dependency를 하나 만들게되고, 서비스의 bottleneck으로 작용할 수 있다.
3-2 RS256 알고리즘
RS256알고리즘은 Asymmetric Key Encrpytion 알고리즘으로, public key와 private key pair를 사용한다. private key는 서명하기 위해 사용되는 key고 public key는 서명된 내용을 검증하는데 사용한다. 따라서 private key는 authentication 서버에서만 가지고 있고, 이 서버에서만 JWT토큰을 생성하면 되기 때문에 private key를 공유할 필요가 없다. 그리고 이 서명을 검증하기 위해서는 외부에 공개되도 되는 public key만 사용하면 되기 때문에 보안적으로 비교적 안전하다.
근데, 여기서 드는 의문은 public key를 어디서 가져오냐 인데, 이를 위해 있는게 바로 Json Web Key Set이다. 서명을 검증하기 위해 필요한 public key의 set이다. 대부분의 JWT를 발급하는 authorization server는 특정 API를 만들어두고, JWT를 검증하기 위해 필요한 public key(JWKS)를 조회하도록 한다.
JWT의 동작방식
JWT는 기본적으로 IdP(Identity Provider)에서 특정 유저의 identity를 증명하기 위해 생성된다. JWT를 활용한 인증 절차는 기본적으로 아래와 같다.
- 유저가 자신의 ID/PW를 입력해 로그인한다. (facebook, google 로그인 포함)
- authentication 서버는 credential을 검증하고, 정보가 맞다면 서명된 JWT를 발급한다. (secret(HS256)나 private key(RS256)를 사용해 서명)
- 유저 클라이언트는 서버에서 자기 자신의 (access protected) 자원에 접근하기 위해 JWT를 HTTP Authorization Header에 담아 보낸다.
- 서버는 토큰의 authenticity를 public key (RS256)나 secret (HS256)를 활용해 토큰의 authenticity를 검증한다.
기존 방식과의 차이
흔히 사용되는 세션 (서버 기반 인증 시스템)에서는 서버측에서 유저들의 정보를 세션에 기억하고 있다. 이를 위해 메모리/디스크/데이터베이스 시스템에 담곤 하는데, JWT는 이와 다르게 Client가 해당 토큰 정보를 보관한다.
JWT의 장점
- 확장성 : 제일 큰 장점이다. 기존 서버에 세션을 저장하는 방식은 분산화된 환경에서 처음 로그인한 서버에만 요청을 보내도록 설정하는 등의 작업이 필요하다. 하지만 토큰은 토큰 값만 알고 있으면 어떤 서버로 요청을 보내던 문제가 되지 않는다.
- 다른 도메인이나, 어플리케이션간 이동이 발생해도 같은 JWT를 사용할 수 있다.
- 쿠키 사용으로 인한 보안 취약점 개선
- 불필요한 인증 과정의 감소 : JWT를 사용하면 사용자와 관련된 정보를 Auth서버에 매번 요청할 필요가 없다. JWT에 정보가 포함돼있기 때문에 개별 서비스들이 자체적으로 토큰의 유효성, 권한 정보 등을 확인할 수 있다.
- HTTPS 사용의 강제성 : Authorization Header에 JWT를 담아 보내기 위해서는 HTTPS를 사용해야 한다.
JWT의 단점
- 토큰이 expire되기 전에 노출되면 보안적으로 매우 취약하다.
- claim이 많아질수록 JWT토큰이 길어진다. 매 호출때마다 토큰 데이터를 서버에 전달하는데, 길이가 길어질수록 네트워크 대역폭 낭비가 심해질 수 있다.
- Payload에 대한 정보는 암호화되지 않고 Base64엔코딩만 하기 때문에 중간에 패킷을 가로채거나 토큰을 취득하게 되면, 데이터를 확인할 수 있다. 이를 해결하기 위해 JWE(Json Web Encryption)을 통해 암호화하거나 중요데이터를 payload에 넣지 않도록 해야 한다.
JWT 사용 팁
Slient Auth : JWT와 Session-Cookie를 모두 사용
JWT의 취약점은 토큰이 노출되면 암호화에 의미가 없어진다는 점이다. 따라서 JWT를 Local Storage에 저장하게 되면 (웹브라우저에서 관리하게 되면) 영구적으로 JWT가 저장되고, 자바스크립트를 통해서도 접근이 가능하기 때문에 보안적으로 매우 취약해진다. 따라서 최소한 메모리에 저장해두는 것이 바람직하다.
하지만 Local Storage에 JWT를 저장하지 않으려면, 사용자가 브라우저를 껐다가 켤 때마다 로그인을 다시 해야 한다. 이는 UX관점에서 너무 별로다.(매번 다시 로그인 해야 하니까) 하지만 재로그인할 때 Cookie를 사용하면 사용자의 경험을 해치지 않고서도 (다시 로그인할 필요 없이)JWT를 재발급받을 수 있다.
위 방식은 사용자의 서비스 경험을 방해하지 않으면서 인증을 다시 하는 방식이다. 재인증을 위해 다시 로그인 창을 띄우지 않고, Hidden iframe에서 인증시 필요한 Redirect처리까지 진행한다. 이때 JWT를 쿠키에 persist하기 위해서는 HttpOnly 쿠키를 생성해야 한다. HttpOnly쿠키를 사용하면 third party의 자바스크립트 코드를 통해서 쿠키 속의 jwt를 읽어내는 것을 방지할 수 있다.
참고자료
https://tech.toktokhan.dev/2021/04/30/JWT/
https://medium.com/@sureshdsk/how-json-web-token-jwt-authentication-works-585c4f076033
https://sureshdsk.dev/how-json-web-token-jwt-authentication-works
https://medium.com/swlh/understand-the-concept-of-jwt-json-web-tokens-4ee18682a583
'웹 개발' 카테고리의 다른 글
[gRPC] grpc 간단 개념 및 서버 / 클라이언트 실행 예제 (정말 쉬운 튜토리얼) (4) | 2022.02.26 |
---|---|
[Jmeter - 부하테스트] Jmeter 기본 개념 / 분산테스트 세팅 / Mac에 설치하는 법 (0) | 2022.02.26 |
[웹 개발] Origin(출처)란 무엇인가? (What is Origin?) (0) | 2022.01.24 |
[웹 개발] CORS란 무엇인가? (what is Cross Origin Request Sharing?) (CORS 한번에 뿌시기) (nginx CORS에러) (0) | 2022.01.24 |
[Session Management (3/3)] Javascript로 구현하고 이해하는 Session Management (0) | 2022.01.23 |