포스트

[WEB] JWT(feat. 쿠키 vs JWT)

1. JWT란?

JWT는 JSON Web Token의 줄임말이다. JSON object를 네트워크를 통해 안전하게 전달하기 위해 설계됐다.

JWT가 사용되는 가장 유명한 분야는 로그인(인증)이다.

2. JWT의 구조.

JWT는 3가지 부분으로 이루어져 있다.

  • HEADER
  • PAYLOAD
  • SIGNATURE

그리고 이 세가지 부분을 “.” 으로 연결해 하나로 만들면 JWT 토큰이 된다.

사진 출처

2.1 HEADER

Header에는 해당 JWT 토큰의 해시 알고리즘과 토큰의 타입을 정의한다.

1
2
3
4
{
	"alg": "HS256",
	"typ": "JWT"
}

이 토큰이 어떤 방식으로 서명 됐는지(alg), 토튼의 종류가 무엇인지(typ)를 나타낸다.

2.2 PAYLOAD

Payload는 토큰에 담을 정보들을 뜻한다.

1
2
3
4
5
6
{
	"sub": "토큰 제목",
	"aud": "토큰 대상자",
	"iat": "토큰 발급 시각",
	"exp": "토큰 만료 시각"
}

각각의 한 줄을 claim 이라고 한다

2.3 SIGNATURE

서명은 JWT 토큰을 받았을 때, 해당 토큰이 서버에서 발급된 토큰이 맞는지 확인하는 역할을 한다.

Header와 Payload는 Base64로 인코딩 되어있어서 누구나 해독이 가능하지만, Signature는 헤더에 포함된 alg, header + payload 내용 + 서버만 알고 있는 secret key 로 함께 만들기 때문에 반드시 서버만 확인 할 수 있다.

3. JWT를 사용하는 이유

전통적인 쿠키를 사용한 인증방식과 JWT 방식을 비교해보자.

3.1 쿠키(세션)를 활용한 인증

  1. 쿠키를 활용한 방식에선 사용자가 로그인을 한 경우 서버에서 session_id를 발급해준다.
  2. 해당 session id는 클라이언트의 브라우저에 저장된다.
  3. 클라이언트가 요청하는 경우 따로 만들어 둔 세션 저장소 db를 확인해 유효한 session id 인지 확인한다.

결론

  1. session_id 자체는 특별한 정보를 포함하고 있지 않아 탈취당한다 해도 별 의미는 없다. 하지만 탈취당한 id를 사용해 클라이언트로 위장하는 경우 식별이 불가능하다.
  2. 클라이언트와 서버가 상호작용할 때마다 세션 저장소에서 유효성 검사를 해야 하므로 서버의 부하가 심해진다.

3.2 JWT 를 활용한 인증

  1. 사용자가 로그인을 한 경우 서버에서 사용자의 정보를 활용해 JWT 토큰을 발급해준다.
  2. 해당 JWT는 클라이언트의 브라우저에 저장된다.
  3. 클라이언트가 요청하는 경우 JWT 토큰을 서버에 전달한다.
  4. 서버에서 서명을 확인해 유효한 서명인지 확인한다.

결론

  1. 초회 로그인 과정 이외엔 이후 요청에서 서버와 DB간의 상호작용이 없다.
  2. 세션 table이 필요없어 서버의 부하를 줄일 수 있다.
  3. 서명을 통하기 정말 민감한 정보의 경우 보안을 지킬 수 있다.
  4. 토큰의 사이즈가 커지면 트래픽에 영향이 있을 수 있고, 토큰 기간만료 처리를 따로 구현해 주어야 한다.

4. JWT가 유출된다면?

만약 JWT가 통째로 유출된다면 어떨까? 서버는 서명으로만 구분하기 때문에 이게 유출된 토큰인지 알 수 없을 것이다.

이 문제점을 해결하기 위해 2가지의 토큰을 동시에 사용한다.

Access Token 평소 API 통신을 할때 사용되고, 짧은 유효기간을 가지고 있다.

Refresh TokenAccess Token을 새로 발급하는데 사용되고 긴 유효기간을 가지고 있다.

실제로 어떤 과정을 가지고 있는지 확인해보자.

  1. 클라이언트가 로그인을 하면 서버로부터 Refresh Token, Access Token 2가지를 받는다.
  2. 클라이언트는 2가지 토큰을 브라우저에 저장해둔다.
  3. API 요청이 있을때는 Access Token을 헤더에 담아 사용한다.
  4. 일정 시간이 지나 Access Token 이 만료된 경우
    1. 권한이 만료 됐으므로 401 에러를 띄워준다.
    2. 401 에러를 받는다면 헤더에 Refresh Token 을 넣어 다시 시도한다.
  5. Refresh Token 의 권한이 살아있다면 새로이 Access Token을 발급해준 후 다시 헤더에 넣어 응답한다.
  6. Refresh Token 에도 401 에러가 나온다면 최종적으로 401 에러를 클라이언트에게 돌려준다.

실제로 유출 됐을 때 위험도가 높은 Access Token의 만료기간을 짧게 해 보안의 안전성을 높인다. 추가적으로 사용자가 짧은 유효기간 때문에 연속적으로 로그인을 해야하는 불쾌한 경험을 지우기 위해 Refresh Token을 사용해 Access Token을 재발급해준다.

4.1 Refresh Token이 유출된다면?

Access Token이 유출엔 짧은 만료기간으로 대응할 수 있다. 하지만 Refresh Token이 유출된다면 위험도가 높을 것이다.

해당 문제를 해결하기 위해 Refresh Token Rotation 을 사용한다.

Access Token이 새로 요청될 때 마다 새로이 Refresh Token을 발급해주는 방식이다.



이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.