JWT
@upswp
JWT 정의
Json Web Token의 약자로 선택적 서명 및 선택적 암호화를 사용하여 데이터를 만들기 위한 웹 표준(RFC 7519)입니다. JWT는 JSON 객체를 사용하여 가볍고 자가 수용적인 방식으로 정보를 안정성있게 전달하는 것에 목적이 있습니다.
- 지원 언어
- C, Java, Python, C++, R, C#, PHP, JavaScript, Ruby, Go, Swift 등 대부분의 주류 프로그래밍 언어에서 지원됩니다.
- 자가 수용적 ( self -contained )
- JWT는 정보 자체를 자체적으로 가지고 있기 떄문에 JWT에서 발급된 토큰 안에는 원하고자 하는 정보값을 암호화한 상태로 전달하며 그 JWT 또한 검증할 수 있는 signature를 포함하면서 자가 수용적인 성격을 가집니다.
어려운 말을 조금 쉽게 풀어내자면 JWT 는 일반적으로 클라이언트와 서버, 서비스와 서비스 사이에서 통신시 권한 인가(Authorization)을 위해 사용하는 토큰입니다. 그렇기에 URL에 대해서 안전한 문자열로 구성이 되어야할 필요가 있고 HTTP 어디든 (URL, Header 등)과 같이 위치할 수 있습니다.
JWT 영역
HEADER.PAYLOAD.SIGNATURE
HEADER
HEADER에서는 JWT를 검증하는데 필요한 정보를 가진 JSON 객체를 가지고 있으며 이 객체는 Base64 URL-Safe 인코딩된 문자열입니다. 헤더는 JWT를 어떻게 검증(Verify)하는가에 대한 내용을 담고 있습니다.
{
"alg" : "HS256",
"typ" : "JWT",
"kid" : "Key ID"
}
여기서 alg는 서명 시 사용한 알고리즘 이고 위의 예제에서는 HS256(HMAC SHA356) 알고리즘을 사용했다는 뜻입니다. 또한 typ은 토큰의 타입을 지정하는 방법으로 이 예제에서는 JWT를 나타내고 있습니다.
Base64URLSafe(UTF-8('{ "alg" : "HS256","typ" : "JWT","kid" : "Key ID"}')) -> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IktleSBJRCJ9
PAYLOAD
Payload 부분에는 토큰에 담을 정보가 들어있습니다. 각각의 정보를 클레임 셋(claim Set) 이라 부르고, 여러 종류의 클레임을 넣을 수 있습니다.
- iss : 토큰 발급자 (issuer)
- sub : 토큰 제목 (subject)
- aud : 토큰 대상자(audience)
- exp : 토큰 만료시간(expiraton), 시간은 NumericData 형식(1480849147370) 언제나 현재 시간보다 이후로 설정되어 있어야합니다.
- nbf : Not Before를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 동일하게 NumericData 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지 토큰이 처리되지 않습니다.
- iat : 토큰 발급된 시간(issued ad), 이 값을 사용하여 토큰의 age가 얼마나 되었는지 판단할 수 있습니다.
- jti : JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위해 사용합니다. 일회용 토큰이 사용되면 좋습니다.
물론 위의 내용들을 전부 넣을 필요는 없다. 하지만 토큰을 만료시키는 시간(exp), 토큰이 발급된 시간(iat)를 포함하는 것이 일반적이다.
SIGNATURE
점(.) 을 구분자로 헤더와 페이로드를 합친 문자열을 서명한 값입니다. 서명은 헤더의 alg에 정의된 알고리즘과 비밀 키를 이용해서 생성하고 Base64 URL로 인코딩 합니다.
추가적인 JWT
Base64 URL-Safe != Base64
Base64 URL-Safe 인코딩은 기본적으로 Base64 인코딩에서 '+'(plus)를 '-'(minus)로, '/'(slash)는 '_'(underscore)로 대체된 인코딩 방법입니다. 이로인해서 JWT는 설계 의도대로 URL, Cookie, Header등 어디에서도 사용될 수 있는 넓은 범용성을 가지게 되었습니다.
Header & Payload
JWT의 헤더는 Base64 인코딩 전 항상 UTF-8로 인코딩된 문자열이어야 합니다. 이유는 헤더가 JSON이어야하고, JSON의 기본 인코딩은 UTF-8이어야 하기 때문입니다. 즉, JOSE( JSON Object Signing and Encryption ) Header다.
자체포함(Self-Contained) & 무상태(Stateless)
JWT는 JWT자체에 필요한 모든 정보를 담을 수 있다. 헤더는 토큰에 대한 해석 방법을, 페이로드는 토큰의 내용 및 전달할 내용(사용자 정보, 권한, 서비스에 필요한 데이터)을 자유롭게 담을 수 있으며, 서명으로 헤더와 페이로드가 위 변조 되지 않았다는 것을 검증할 수 있다. 서버는 JWT 생성 시 JWT에 검증이나 권한 인가 시 필요한 값을 넣으면 되기 때문에 JWT에 대한 상태를 따로 관리하지 않아도 된다.
JWT as API Key
애플의 푸시 메시지 발송 API인 APNs Provider API는 2016년부터 인증을 위해 JWT를 지원하기 시작했다. 기존에는 1년동안 사용가능한 인증서를 애플 개발자 콘솔에서 발급받아 mTLS(Mutual TLS)를 통해 API 인증을 했었다. JWT를 API Key로 사용하면서 앞서 말한 성질들 덕분에 APNs는 mTLS방식에 비해 빠르게 API를 인증할 수 있게 되었다. 아래와 같은 과정을 거치면서 APNs Provider API를 호출하는 과정은 아래와 같다.
- 애플 개발자 콘솔에서 JWT 생성에 필요한 키 아이디, 발행인, 비밀키를 발급받는다.
- API 호출 전 발급받은 값을 이용해 JWT를 생성한다.
- API 호출 시 Authorization 헤더에 JWT를 추가한다.
- APNS는 Authorization 헤더에 있는 JWT를 인증한다.
JWT in MSA
Access Token in MSA
일반적으로 권한에 따른 접근제어가 필요한 웹 서비스는 먼저 로그인을 통해 사용자 인증(Authentication)을 진행한다. 권한 서비스(Authorization Service)는 인증을 통과한 클라이언트에게 엑세스 토큰을 발급한다. 수 많은 서비스 간 API 호출이 발생하는 MSA(Micro Service Architecture)나 클라우드 환경에서는 엑세스 토큰이 가리키는 권한을 확인하기 위해 모든 서비스들이 권한 서비스와 통신을 해야한다. 서비스가 늘어날 수 록 권한 서버가 받는 부하가 기하급수적으로 증가할 수 있다. 이 부분을 JWT를 이용한다면 MSA의 확장성 (Scalability) 측면에서 부담을 줄여줄 수 있다. 아래의 사진은 JWT를 사용하기 이전의 참조토큰(By Reference Token)을 사용한 그림이다.
JWT as Access Token in MSA
참조토큰 대신에 JWT를 액세스 토큰으로 사용할 수 있다. JWT는 자체적으로 필요한 정보를 모두 담을 수 있기 때문에 값 토큰(By Value Token)이라고 한다. JWT 엑세스 토큰은 MSA 환경의 인증과 접근 제어에 접합하다. 서비스는 JWT에 포함된 값을 기준으로 권한을 확인할 수 있다. 서비스와 권한 서비스의 통신은 JWT 서명을 인증하기 위한 공개키를 조회하는게 전부이다.
JWT를 사용했을때, 단점으로는 사용자의 정보가 변경되었을 경우, JWT를 새로 발급해야하는 단점이 있다. 또한 JWT의 헤더와 페이로드의 값을 디코딩 하여 확인하면 정보값을 확인할 수 있기 때문에 클라이언트에 공개되는 단점이 있다. 이 부분에서 외부에 노출이 되어서는 안되는 보안 정보를 피해 JWT를 사용해야한다.
API Gateway between Access Token and JWT in MSA
클라이언트, 권한 서비스, 서비스 사이에 API Gateway를 위치시키면 JWT를 클라이언트에게 숨기면서 서비스간 통신할때 사용할 수 있게 된다. API Gateway는 클라이언트에게 받은 엑세스 토큰을 권한 서비스를 통해 JWT로 받아 엑세스 토큰 대신 서비스로 넘겨준다.
참고
'Web > etc' 카테고리의 다른 글
M1 기반 환경세팅 (0) | 2022.03.05 |
---|---|
Swagger (0) | 2021.02.23 |