- JWT의 사용
- JWT란?
- JWT의 구조
- 세션과 JWT
- Access Token과 Refresh Token
- 프로젝트에 적용할 수 있는 부분
JWT(Json Web Token)는 웹 표준(RFC 7519)으로서 두 개체에서 JSON 객체를 사용해 가볍고 자가수용적인 방식으로 정보를 안정성 있게 전달해준다.
JWT는 사용자의 인가(Authorization)를 위해 사용한다.
JWT는 .을 구분자로 3가지의 문자열로 구성된다.

특징
- 자가수용적이다. (Self - contained)
JWT는 필요한 모든 정보를 자체적으로 지니고 있다.
JWT 시스템에서 발급된 토큰은 토큰에 대한 “기본 정보, 전달 할 정보, 토큰이 검증”되었다는 것을 증명해 주는signature(특징적인 표시)를 포함하고 있다.- 가볍게(쉽게) 전달할 수 있다.
JWT는 자가수용적(self-contained)적이기 때문에 두 개체에서 손쉽게 전달 될 수 있다.
웹 서버의 경우 HTTP 헤더에 넣어서 전달 또는 URL의 파라미터로 전달 할 수 있다.
헤더 (Header)
- typ과 alg 두 가지 정보를 지님
- typ : 토큰의 타입
- JWT는 “JWT” 타입을 사용
- alg : 해싱 알고리즘 지정
- HMAC, SHA256, RSA을 사용.
- 위 알고리즘은 토큰을 검증 할 때 사용되는 signature 부분에 사용.
{ "typ" : "JWT", "alg" : "HS256" }
내용 | 정보 (payload)
- 토큰을 담을 정보가 들어 있다.
- 정보의 한 조각 ⇒ 클레임(claim)
- name : value 구조
- 토큰에는 여러 클레임을 넣을 수 있다.
- 클레임이 너무 많아지면 토큰의 길이가 길어진다.
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
클레임 (claim) 분류
- 등록된(registered) 클레임
- 등록된 클레임들은 서비스에서 필요한 정보들이 아닌,
토큰에 대한 정보들을 담기 위하여 이름이 이미 정해진 클레임이다.- 등록된 클레임의 사용은 모두 선택적(optional)이다.
- 등록된 클레임 종류
iss: 토큰 발급자 (issuer)sub: 토큰 제목 (subject)aud: 토큰 대상자 (audience)exp: 토큰의 만료시간(expiration)
- 시간은 NumericDate 형식
- 예) YYYYMMDDHHMMSS 20240713134530
- 언제나 현재 시간보다 이후로 설정되어 있어야 한다.
nbf: Not before을 의미하며, 토큰의 활성 날짜와 비슷한 개념
- NumericDate형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다.
iat: 토큰이 발급된 시간(issued at)
- 토큰이 얼마나 되었는지 판단 할 수 있다.
jti: JWT의 고유 식별자로서
- 주로 중복적인 처리를 방지하기 위하여 사용된다
- 일회용 토큰에 사용하면 유용하다.
- 공개(public) 클레임
- 공개 클레임들은 충돌이 방지된(collision-resistant)이름을 가지고 있어야 한다.
- 충돌을 방지하기 위해서는, 클레임 이름을 URI형식으로 짓는다.
- 비공개(private) 클레임
- 등록된 클레임도 아니고, 공개된 클레임들도 아닌 클레임.
- 양 측간에(보통 클라이언트 <-> 서버) 합의하에 사용되는 클레임 이름
- 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 주의
서명(signature)
서명은 헤더의 인코딩값과 정보/내용의 인코딩값을 합친 후 주어진 비밀키로 해쉬를 하여 생성합니다. 이렇게 만든 해쉬를base64형태로 나타내게 된다.
서명은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다. 서명은 위서 만든 헤더와 페이로드의 값을 각각 BASE64로 인코딩 하고, 인코딩 한 값을 비밀 키를 이용하여 헤더에서 정한 알고리즘으로 해싱을 하고, 이 값을 다시 BASE64로 인코딩 하여 생성한다.
어떤 놀이공원에 방문한 회원이 놀이기구를 타려고 하는 상황을 가정해 보자.
유저→서버: 유저가 놀이공원에 방문하면
서버→유저: 입장권 발급
유저→서버: 이후 유저가 놀이기구 탈때 마다 입장권을 확인함.
서버→유저: 문제 없으면 유저 태움, 문제있으면 안 태움
세션
입장권 발급번호 외 입장권에 정보가 별로 없다.
서버가 입장권을 발급해 줄때 db에 발급번호를 세션store에 저장한다.
이후 입장권을 확인할때 세션store에서 확인한다.
- 단점
입장권 발급 수가 늘어나면 그만큼 state를 많이 유지하기 때문에 조회하는 데 오래 걸리고 서버에 부담이 된다.
토큰(JWT)
입장권 자체에 정보(유저 정보)가 많다.
토큰정보 중 유효기간 정보를 확인해 유효기간에 문제가 없다면 유저를 통과시킨다.
- 장점
stateless : 유저 수가 많아질수록 서버 부담이 덜해진다.
만약 유효기간이 짧은 Token을 발급하게되면 사용자 입장에서 자주 로그인을 해야하기 때문에 번거롭고 반대로 유효기간이 긴 Token을 발급하게되면 제 3자에게 토큰을 탈취당할 경우 보안에 취약하다는 약점이 있다.
그 점들을 보완하기 위해 Refresh Token 을 사용할 수 있다.
Refresh Token은 Access Token과 똑같은 JWT이다. Access Token의 유효기간이 만료되었을 때, Refresh Token이 새로 발급해주는 열쇠가 된다.
예를 들어, Refresh Token의 유효기간은 1주, Access Token의 유효기간은 1시간이라고 한다면, 사용자는 Access Token으로 1시간동안 API요청을 하다가 시간이 만료되면 Refresh Token을 이용하여 새롭게 발급한다.
이 방법또한 Access Token이 탈취당한다해도 정보가 유출이 되는걸 막을 수 없지만, 더 짧은 유효기간때문에 탈취되는 가능성이 적다는 점을 이용한 것이다.
Refresh Token또한 유효기간이 만료됐다면, 사용자는 새로 로그인해야 한다. Refresh Token도 탈취 될 가능성이 있기 때문에 적절한 유효기간 설정이 필요하다.
현재 프로젝트에는 Access Token만을 발급하고 있다. 즉, 토큰 탈취의 문제점이 있다. Refresh Token을 발급해 비교적 Access Token의 유효기간을 짧게 설정한다면, 어느 정도 이러한 문제점을 해결할 수 있을 것으로 기대된다.