웹 애플리케이션 인증 방식 2 : JWT

KDG: First things first!·2024년 8월 30일
0

CS

목록 보기
6/6


해당 포스팅의 내용은 웹 애플리케이션 인증 방식 1 : 쿠키-세션에 이어집니다.




JWT란?

JWT(Json Web Token): JWT는 인증과 인가에 사용하기 위해 JSON 형식으로 이루어진 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다. JWT는 인증, 인가, 정보 교환, 그리고 클레임(Claim)을 안전하게 전송하는데 자주 사용된다.

(※ 클레임(Claim): 토큰에 담겨지는 정보)




JWT 사용 이유와 장단점


흔히 상당수의 IT 서비스는 대용량 트래픽 처리를 위해 여러 대의 서버를 운영한다. 하지만 여러 대의 서버를 운영하는 환경에서 서버에 클라이언트의 로그인 정보를 저장한다면 해당 클라이언트는 무조건 해당 서버하고만 통신해야 한다는 문제점이 생긴다.

물론 Client 마다 요청 Server 고정하는 Sticky Session 방식을 사용하거나 서버에 세션 저장소를 별도로 만들어 모든 세션을 저장하면 문제가 해결되지만 클라이언트가 한 서버만 이용 가능하거나 서버에 별도의 대용량의 저장소를 만들어 운영하는 것은 서버에게 매우 큰 부담이 될 수 있기 때문에 두 가지 다 효율적인 방식이라고는 할 수 없다.


실제로 일반적으로 다수의 서버를 운영하는 경우에는 서버 앞단에 Load Balancer가 존재하여 한 서버에만 다수의 클라이언트의 요청이 몰리지 않고 골고루 배분되도록 하는 시스템을 채택한다.


JWT 인증 방식을 사용하면 로그인 정보를 서버에 저장하지 않고 모든 서버가 공유하는 Sercret Key를 이용하여 JWT로 암호화하고 클라이언트에 발급, 저장하고 JWT를 담은 클라이언트의 요청이 올 때마다 Sercret Key로 해당 토큰에 대한 복호화를 이용하여 인증/인가를 진행할 수 있기 때문에 위의 문제점들을 해결할 수 있다.



JWT의 장점

  • 서버에 요청이 많을 시에 서버 측의 부하를 낮춰준다.

  • 클라이언트, 서버가 다른 도메인을 사용하는 경우가 많은 OAuth을 사용할 때 편리하다.



JWT의 단점

  • 구현이 상대적으로 복잡하다.

  • JWT 에 담는 내용이 커질수록 클라이언트-서버간의 네트워크 비용이 증가한다.

  • 이미 생성된 JWT를 고의적으로 만료시키는 것이 불가능하다.

    • Secret key가 유출될 시 JWT 조작이 가능하다는 보안 취약점이 존재한다.



JWT 구조


JWT는 Header, Payload, Signature의 3 부분으로 이루어진다. 각 부분은 JSON 형태로 되어 있는데 Base64Url로 인코딩 되어 나타난다. 또한 각각의 부분은 . 구분자를 통해 구분된다.

(Base64Url는 암호화된 문자열이 아니고, 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환하는 방식이

다.)


JWT 확인 사이트: https://jwt.io/

해당 사이트에서 갖고 있는 JWT 토큰을 decoding하여 JWT에 담긴 정보를 확인할 수 있다.



HTTP 프로토콜에서는 JWT를 key-value 형태로 사용하는데 흔히 key로는 "Authorization"이라는 값을 사용하고 value로는 "Bearer "을 붙인 토큰 값을 사용한다.

{ 
    "Authorization": "Bearer 발급된 토큰 값"
 }




1. Header(헤더)


헤더는 토큰의 타입(typ)해싱 알고리즘(alg)이라는 두 가지 정보를 포함한다.

예를 들어, 토큰이 JWT이고 HMAC SHA256 알고리즘을 사용하는 경우 예시는 다음과 같다.


{
  "typ": "JWT",
  "alg": "HS256"
}

해당 JSON 객체는 Base64Url 인코딩되어 JWT의 첫 번째 부분이 된다.
(alg는 필수 필드이지만 typ은 선택 필드여서 없을 수도 있다.)




2. Payload(페이로드)


페이로드는 토큰에 저장될 정보, 즉 클레임(Claim)을 담고 있다.
클레임은 일반적으로 토큰의 주체(sub), 발행인(iss), 만료 시간(exp) 등과 같은 정보를 포함한다.


(Payload 예시)

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

페이로드에 실제 유저와 관련된 정보가 들어 있다고 생각하면 된다.
이 페이로드 역시 Base64Url 인코딩되어 JWT의 두 번째 부분을 형성한다.




3. Signature(서명)


서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.

서명은 헤더와 페이로드의 조합에 대해 비밀 키를 사용하여 해싱 알고리즘으로 생성된다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

위에서 만든 헤더와 페이로드의 값을 각각 BASE64Url로 인코딩한 후 해당 값들을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱을 하고, 이 값을 다시 BASE64Url로 인코딩하여 생성하는 과정을 거친다.

이 서명이 JWT의 세 번째 부분을 형성한다.





JWT 기반 인증 동작 방식

JWT를 기반으로 한 인증은 다음과 같은 원리와 순서로 동작한다.


1. 사용자가 로그인을 시도하여 서버에 로그인 요청이 보내진다.

2. 서버는 로그인 요청을 받으면 사용자에게 입력받은 ID(혹은 Email), Password를 회원의 정보가 저장되어 있는 DB에서 회원 정보를 가져와 대조하여 검증한다.

3. 만약 데이터가 일치하여 해당 사용자 인증에 성공하면 유저의 정보를 암호화한 JWT를 발급한다.

4. 서버가 로그인에 대한 응답에 JWT를 실어 클라이언트에 반환한다.

5. 클라이언트는 해당 토큰을 보관하다가 서버에 요청을 보낼 때마다 Header에 토큰을 실어 같이 전송한다.

6. 클라이언트의 요청을 받으면 서버는 해당 토큰이 올바른지(유효한 형식인지, 유효 시간이 남은 토큰인지, 해당 사용자에게 발급된 토큰이 맞는지 등등)를 검증한다.

7. 토큰이 성공적으로 검증되었으면 클라이언트에 요청을 처리하여 응답을 반환한다.

profile
알고리즘, 자료구조 블로그: https://gyun97.github.io/

0개의 댓글