목차
JWT란?
JWT(JSON Web Token)
- 어떠한 사용자가 아이디와 비밀번호를 사용하여 로그인을 하면,사용자의 정보를 가진 토큰이 발행되어 서버에 요청을 보낼때마다 세션, 쿠키 대신에 JWT 토큰을 이용해서 서버로 보내어 요청을 보낸 사용자가 누구인지 특정을 할 수 있다.
JWT의 구조
👉 HEADER . PAYLOAD . SIGNATURE
헤더 내용 서명
Header(헤더)
- 토큰의 헤더는 typ와 alg 두 가지 정보로 구성된다. alg는 Signature를 해싱하기 위한 알고리즘을 지정하는 것.
Payload(페이로드)
- 토큰의 페이로드에는 **토큰에서 사용할 정보의 조각들인 클레임(Claim)**이 담겨 있다.
- 클레임은 총 3가지로 나누어지며, JSON(Key/Value) 형태로 다수의 정보를 넣을 수 있다.
- 필수로 exp(토큰의 만료시간)을 지정하여 토큰이 탈취 당했을 때를 대비하여 일정 시간 이후에 토큰이 만료될 수 있도록 하여야 한다.
등록된 클레임(Registered Claim)
- iss: 토큰 발급자(issuer)
- sub: 토큰 제목(subject)
- aud: 토큰 대상자(audience)
- exp: 토큰 만료 시간(expiration), NumericDate 형식으로 되어 있어야 함 ex) 1480849147370
- nbf: 토큰 활성 날짜(not before), 이 날이 지나기 전의 토큰은 활성화되지 않음
- iat: 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간을 알 수 있음
- jti: JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용
공개 클레임(Public Claim)
- 공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용한다.
비공개 클레임(Private Claim)
- 비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
Signature(서명)
- Signature(서명)은 토큰을 인코딩하거나 유효성 검증을 위해 사용하는 고유한 암호화 코드이다.
- Header와 Payload를 각각 Base64로 인코딩한 후 합쳐서 Header에 명시된 서명 알고리즘과 비밀키를 통해 해쉬값으로 만들어집니다. 만들어진 해쉬값을 Base64로 한번 더 인코딩하면 JWT에 담기는 시그너치가 됩니다.
— 비밀키를 기반으로 서명 알고리즘이 해쉬값을 생성하기 때문에 예측가능하거나 노출되면 안됩니다.
JWT 토큰 만료 시
- AccessToken을 약간 긴 만료시간으로 발급
- 만료 시 재 로그인
- 짧은 만료시간의 AccessToken + 상대적으로 긴 RefreshToken
- AccessToken 만료 시 서버로 RefreshToken을 보내 AccessToken을 재발급
- RefreshToken 까지 만료 시 재로그인
JWT Server ↔ Client 통신
- 클라이언트가 로그인 작업을 수행 시 서버는 해당 사용자를 특정 할 수 있도록 JWT토큰을 발행하고 서버 → 클라이언트로 토큰을 보내주고 클라이언트는 쿠키, 세션 스토리지 등에 저장을 한다
- 클라이언트가 서버에 요청을 할 때마다 Header에 JWT토큰 넣어 서버로 보내준다.
{ "Authorization": "Bearer {생성된 토큰 값}", }
JWT토큰을 받은 서버측
- 토큰 파싱 : 수신한 JWT를 파싱하여 헤더, 페이로드, 서명으로 분리
- 서명 검증 : 헤더와 페이로드, 비밀 키를 사용하여 수신된 서명과 동일한 서명을 생성 이때 사용하는 알고리즘은 JWT 헤더에 명시된 알고리즘 사용
- 유효성 검사 : 서버가 생성한 서명과 수신된 서명이 일치하는지 확인, 만약 일치하지 않는다면 토큰이 변조되거나 유효하지 않은 토큰이라는 응답을 보낸다.
- 추가 검증 : 토큰의 만료 시간(expiration time), 발급자, 토큰의 용도, 내부의 데이터들에 추가적인 검증을 수행할 수 있다.
JWT 단점 및 고려사항
- Self-contained : 토큰 자체에 정보를 담고 있으므로 양날의 검이 될수도 있다.
- 토큰 정보량 : 토큰의 Payload(페이로드)에 정보를 많이 저장할 수록 토큰의 길이가 늘어나 서버와 클라이언트 간의 통신 데이터양이 늘어나 서버에 부하를 줄 수 있다.
- Payload 인코딩 : Payload(페이로드) 자체는 암호화 된 것이 아니라, Base64로 인코딩 된 것이기 때문에, 탈취 당했을 때 Base64로 디코딩을 하면 원 데이터를 볼 수가 있어 JWE로 암호화를 하거나 Payload에 중요한 데이터를 넣지 말아야 한다.
- Stateless: JWT는 상태를 저장하지 않기 때문에 한번 만들어지면 제어가 불가능하다. 즉, 토큰을 임의로 삭제하는 것이 불가능하므로 토큰 만료 시간을 꼭 넣어주어야 한다.
- Tore Token: 토큰은 클라이언트 측에서 관리해야 하기 때문에, 토큰을 저장해야 한다.
JWT란?
JWT(JSON Web Token)
- 어떠한 사용자가 아이디와 비밀번호를 사용하여 로그인을 하면,사용자의 정보를 가진 토큰이 발행되어 서버에 요청을 보낼때마다 세션, 쿠키 대신에 JWT 토큰을 이용해서 서버로 보내어 요청을 보낸 사용자가 누구인지 특정을 할 수 있다.
JWT의 구조
👉 HEADER . PAYLOAD . SIGNATURE
헤더 내용 서명
Header(헤더)
- 토큰의 헤더는 typ와 alg 두 가지 정보로 구성된다. alg는 Signature를 해싱하기 위한 알고리즘을 지정하는 것.
Payload(페이로드)
- 토큰의 페이로드에는 **토큰에서 사용할 정보의 조각들인 클레임(Claim)**이 담겨 있다.
- 클레임은 총 3가지로 나누어지며, JSON(Key/Value) 형태로 다수의 정보를 넣을 수 있다.
- 필수로 exp(토큰의 만료시간)을 지정하여 토큰이 탈취 당했을 때를 대비하여 일정 시간 이후에 토큰이 만료될 수 있도록 하여야 한다.
등록된 클레임(Registered Claim)
- iss: 토큰 발급자(issuer)
- sub: 토큰 제목(subject)
- aud: 토큰 대상자(audience)
- exp: 토큰 만료 시간(expiration), NumericDate 형식으로 되어 있어야 함 ex) 1480849147370
- nbf: 토큰 활성 날짜(not before), 이 날이 지나기 전의 토큰은 활성화되지 않음
- iat: 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간을 알 수 있음
- jti: JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용
공개 클레임(Public Claim)
- 공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용한다.
비공개 클레임(Private Claim)
- 비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
Signature(서명)
- Signature(서명)은 토큰을 인코딩하거나 유효성 검증을 위해 사용하는 고유한 암호화 코드이다.
- Header와 Payload를 각각 Base64로 인코딩한 후 합쳐서 Header에 명시된 서명 알고리즘과 비밀키를 통해 해쉬값으로 만들어집니다. 만들어진 해쉬값을 Base64로 한번 더 인코딩하면 JWT에 담기는 시그너치가 됩니다.
— 비밀키를 기반으로 서명 알고리즘이 해쉬값을 생성하기 때문에 예측가능하거나 노출되면 안됩니다.
JWT 토큰 만료 시
- AccessToken을 약간 긴 만료시간으로 발급
- 만료 시 재 로그인
- 짧은 만료시간의 AccessToken + 상대적으로 긴 RefreshToken
- AccessToken 만료 시 서버로 RefreshToken을 보내 AccessToken을 재발급
- RefreshToken 까지 만료 시 재로그인
JWT Server ↔ Client 통신
- 클라이언트가 로그인 작업을 수행 시 서버는 해당 사용자를 특정 할 수 있도록 JWT토큰을 발행하고 서버 → 클라이언트로 토큰을 보내주고 클라이언트는 쿠키, 세션 스토리지 등에 저장을 한다
- 클라이언트가 서버에 요청을 할 때마다 Header에 JWT토큰 넣어 서버로 보내준다.
{ "Authorization": "Bearer {생성된 토큰 값}", }
JWT토큰을 받은 서버측
- 토큰 파싱 : 수신한 JWT를 파싱하여 헤더, 페이로드, 서명으로 분리
- 서명 검증 : 헤더와 페이로드, 비밀 키를 사용하여 수신된 서명과 동일한 서명을 생성 이때 사용하는 알고리즘은 JWT 헤더에 명시된 알고리즘 사용
- 유효성 검사 : 서버가 생성한 서명과 수신된 서명이 일치하는지 확인, 만약 일치하지 않는다면 토큰이 변조되거나 유효하지 않은 토큰이라는 응답을 보낸다.
- 추가 검증 : 토큰의 만료 시간(expiration time), 발급자, 토큰의 용도, 내부의 데이터들에 추가적인 검증을 수행할 수 있다.
JWT 단점 및 고려사항
- Self-contained : 토큰 자체에 정보를 담고 있으므로 양날의 검이 될수도 있다.
- 토큰 정보량 : 토큰의 Payload(페이로드)에 정보를 많이 저장할 수록 토큰의 길이가 늘어나 서버와 클라이언트 간의 통신 데이터양이 늘어나 서버에 부하를 줄 수 있다.
- Payload 인코딩 : Payload(페이로드) 자체는 암호화 된 것이 아니라, Base64로 인코딩 된 것이기 때문에, 탈취 당했을 때 Base64로 디코딩을 하면 원 데이터를 볼 수가 있어 JWE로 암호화를 하거나 Payload에 중요한 데이터를 넣지 말아야 한다.
- Stateless: JWT는 상태를 저장하지 않기 때문에 한번 만들어지면 제어가 불가능하다. 즉, 토큰을 임의로 삭제하는 것이 불가능하므로 토큰 만료 시간을 꼭 넣어주어야 한다.
- Tore Token: 토큰은 클라이언트 측에서 관리해야 하기 때문에, 토큰을 저장해야 한다.