JWT(JSON Web Token)
얼마 전에 WAS를 구현하느라 쿠키나 세션이 아닌 토큰을 사용해 볼 기회가 있었다. jwt.io에 가보면 JSON Web Token에 대한 자세한 설명을 볼 수 있고, 토큰을 디코딩할 수 있다.
JWT(JSON Web Token) 란?
- JWT는 JSON을 이용한 토큰이며, 다음과 같은 구조를 가진다.
1) Header : 암호화 알고리즘 및 Type
- typ : 토큰 타입, JWT만 존재
- alg : 해싱 알고리즘(HMAC SHA256 또는 RSA) 헤더 자체를 암호화하는 것이 아닌 토큰 검증 시에 사용된다.
2) Payload : 실제 토큰으로 사용하려는 데이터가 담긴 부분
- Reserved claims : 이미 예약된 Claim
- iss(String) : issuse, 토큰 발행자 정보
- exp(Number) : expiration time, 만료일
- sub(String) : subject, 제목
- aud(String) : audience
- Public claims : 사용자 정의 Claim
- 공개용 정보, URI 포맷을 이용해 저장
- Private cliams : 사용자 정의 Claim
- 사용자가 임의로 정한 정보
3) Signature : Header와 Payload의 데이터 무결성과 변조 방지를 위한 서명
- Header와 Payload를 합친 후 Secret 키와 함께 Header의 해싱 알고리즘으로 인코딩
JWT의 인증방식
- 토큰 기반 시스템은 상태유지를 하지 않으므로 stateless 하다.
- 클라이언트가 토큰을 서버에 전달할 때 HTTP 요청 헤더에 포함시켜 전달한다.
JWT의 문제점
1) 길이
- Claim에 넣는 데이터와 JWT 토큰의 길ㅑ이는 비례한다. 클라이언트가 요청할 때마다 헤더에 토큰이 붙어 전송되므로, 네트워크 대역폭 낭비가 심하다.
2) 한번 발급된 토큰 값의 수정 및 폐기 불가능
- JWT는 토큰 내에 모든 정보를 가지고 있어 한번 발급된 토큰을 서버가 변경할 수 없다. 그렇기 때문에 Reserved Claims에 expiration time을 꼭 지정해주고, refresh token 등을 통해 토큰을 재발급해주어야 한다.
3) 보안
- 기본적으로 Claim을 암호화 하지 않고 단순히 base64 인코딩만을 하기 때문에 토큰이 타인에게 노출되면 사용자 정보가 유출될 수 있다.
- Payload에 권한과 관련된 Claim을 넣어 그 값으로만 사용자를 식별한다면 토큰 값 조작으로 인가되지 않은 접근 권한을 획득할 수 있다.
보안 고려사항
1) Signature Stripping
- JWT 공격 방법 중 signature를 제거하는 것이 흔하다. 잘못된 검증으로 unsigned 상태인 토큰을 유효한 토큰으로 인식할 수 있으므로 애플리케이션에서 unsigned 토큰을 유효하지 않은 토큰으로 인식하도록 하면 된다.
2) CSRF(Cross-Site Request Forgery)
- 토큰이 쿠키에 저장되는 경우, short-lived JWT를 이용하거나, origin 검증을 통해 CSRF 공격을 방어할 수 있다. 토큰이 쿠키에 저장되어있지 않으면 CSRF 공격은 불가능하다.
3) XSS(Cross-Site Scripting)
- 액세스 토큰이 만료되기 전에 유출되면, 리소스에 접근하는 용도로 사용될 수 있다. 클라이언트에서 보낸 데이터를 반드시 sanitize 하고, 쿠키에 대해선 HttpOnly flag를 설정해 스크립트 코드로 접근하는 것을 막아야 한다.