관리 메뉴

공부기록용

CS_ JWT 방식과 사용이유 본문

💡깨달음💡/CS

CS_ JWT 방식과 사용이유

과부하가즈아 2023. 6. 24. 23:54

🖇️서버가 클라이언트 인증을 확인하는 방식


🔴JWT란,

🔴JWT구조

🔴JWT의 방식

🔻특징

🔻한계

🔴JWT의 Access Token / Refresh Token

🔴서버 세션 인증 방식과 JWT인증의 차이


기존 쿠키 세션 동작 방식과 문제점

  • 저장 공간의 용량
    • 세션은 서버의 메모리 내부에 저장이 된다. 유저가 한두명일때야 메모리에 무리가 가지 않겠지만 유저가 수천명인 대형 서비스에서는 세션의 양이 많아지는 만큼 메모리에 부하가 걸릴 수 있다.
  • 확장성의 문제
    • 서비스의 규모가 커져서 서버를 여러대로 확장 및 분산해야 한다면 세션을 분산시키는 기술을 따로 설계해야 한다.

이를 해결하기 위해 보통 JWT라는 로그인 방식을 도입


JWT

JWT(Json Web Token)는 말그대로 웹에서 사용되는 JSON 형식의 토큰에 대한 표준 규격으로 JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다. 이름에 있는 JSON 명칭에서도 알 수 있듯이 JSON으로 만들어진 인증 관련 정보를 인코딩한 토큰을 이용하여 인증하는 방식이다. JWT는 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달한다.

 

서버에 세션 정보를 저장하지 않고, 로그인 시 클라이언트에게 로그인 사용자 정보가 포함된 토큰을 발행하고,

클라이언트는 서버에 어떤 작업을 요청할 때 마다 이 토큰을 같이 보내고,

서버는 이 토큰에 포함된 사용자 정보를 이용해서 서버와 클라이언트 간에 안전하게 주고 받을 수 있도록 사용자의 인증(authentication), 인가(authorization)을 처리하는 방식입니다.

 

인증을 유지한다는 개념보다는 인증된 값을 계속 제공한다고 볼 수 있습니다.

 

토큰(token),
서버가, 각각의 클라이언트를 누군지 정확히 구별할 수 있도록,유니크한 정보를 담은 암호화 데이터이다.

유저 구별이 가능해야, 유저의 권한에 맞는 정확한 기능을 응답할 수 있다.
( 사용자 구분 및 정보 유출방지 )

인증,
어떤 개체(사용자 또는 장치)의 신원을 확인하는 과정

인가,
어떤 개체가 어떤 리소스에 접근할 수 있는지 또는 어떤 동작을 수행할 수 있는지를 검증하는 것, 즉 접근 권한을 얻는 일


JWT 구조

JWT의 내부 구조는 세가지의 문자열의 조합이다. 실제 디코딩 되어있는 JWT 를 살펴보면Header,Payload,Signature로 이루어져 있다. 각 구역은 (.)으로 구분되며, JSON 형태인 각 부분은 BASE64로 인코딩 되어 표현된다.

 

헤더(header)

토큰의 타입과 해시 암호화 알고리즘으로 구성된다. alg는 헤더를 암호화 하는 것이 아닌, Signature를 해싱하기 위한 알고리즘을 지정하는 것이다.

{
  "alg": "HS256",
  "typ": "JWT"
}
  • typ : 토큰의 타입을 지정한다.
  • alg : 알고리즘 방식을 지정하며, 서명(Signature) 및 토큰 검증에 사용한다. 

페이로드(payload_내용)

토큰에 사용자가 담고자 하는 정보를 담는 곳으로 소위 claim이라고도 불리는 사용자의 인증/인가 정보가 담긴다. 표준 스펙상 key의 이름은 3글자로 되어있다. JWT의 핵심 목표는 사용자에 대한, 토큰에 대한 표현을 압축하는 것이기 때문에 이를 정의한 것이다.

 

claim

JWT 를 이용해 전송되는 암호화된 정보를 말한다. JSON 오브젝트에서 다루는 프로퍼티의 이름이기도 하다. ex) { "sub": "12345" } 에서 sub 는 subject claim 이다.

 

JWT 토큰은 네트워크로 전송되야 하기 때문에 공간을 적게 차지하는 것이 유리하다. 그래서 독특하게도 JSON 형식으로 데이터를 저장할 때 키(key)를 3글자로 줄이는 관행이 있다.

{
 "iss": "dev-coco.tistory.com",
 "exp": "1602076408",
 "https://dev-coco.tistory.com/jwt": true,
 "userId": "dev-coco"
 "username": "coco"
}

 

key의 이름

iss (Issuer) : 토큰 발급자
sub (Subject) : 토큰 제목 - 토큰에서 사용자에 대한 식별값이 됨
aud (Audience) : 토큰 대상자
exp (Expiration Time) : 토큰 만료 시간
nbf (Not Before) : 토큰 활성 날짜 (이 날짜 이전의 토큰은 활성화 되지 않음을 보장)
iat (Issued At) : 토큰 발급 시간
jti (JWT Id) : JWT 토큰 식별자 (issuer가 여러명일 때 이를 구분하기 위한 값)

이러한 표준 스펙으로 정의되어있는 Claim 스펙이 있다는 것이지, 꼭 이 7가지를 모두 포함해야하는 것은 아니고, 상황에 따라 해당 서버가 가져야할 인증 체계에 따라 사용하면 된다.

 

✨다만 가장 중요한 것은 payload에 민감한 정보를 담지않는 것이다. 위에 header와 payload는 json이 디코딩되어있을 뿐이지 특별한 암호화가 걸려있는 것이 아니기 때문에 누구나 jwt를 가지고 디코딩을 한다면 header나 payload에 담긴 값을 알 수 있기 때문이다.

 
JWT에서 header와 payload는 특별한 암호화없이 흔히 사용할 수 있는 base64 인코딩을 사용하기 때문에 서버가 아니더라도 그 값들을 확인할 수 있다. 그래서 JWT는 단순히 "식별을 하기위한" 정보만을 담아두어야하는 것이다.


🔻왜 header나 payload가 식별값만 존재하지만 해당 값들도 암호화를 통해 감추지 않나

 암호화는 민감한 정보를 막아두어야할 때는 필요한 행위이지만 이 자체만으로도 많은 리소스를 사용하기 때문에 신중하게 사용해야한다. (매 http 요청마다 한번의 복호화가 더 추가되는 셈) 그렇기 때문에 유출되었을 때 그렇게 큰 상관이 없는 비민감정보를 토큰에 담는 것이 기본 스펙된 것이고, 서버는 굳이 header나 payload를 암호화하지 않아도 된다.

 

서명(signature)

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

 

헤더(Header)와 내용(Payload)의 값을 각각 BASE64로 인코딩하고, 인코딩한 값을 비밀키를 이용해 헤더에서 정의한 알고리즘으로 해싱하고, 이 값을 다시 BASE64로 인코딩하여 생성한다.

 


Header + Payload + Signature


코드를 Decoded

JSON으로 만들어진 인증 관련 정보를 인코딩한 토큰(데이터가 JSON으로 이루어져 있는 토큰)을 이용하여 인증하는 방식

  1. 사용자 로그인 시 서버는 사용자 인증을 완료하고 외부에 노출되어도 문제가 없는 인증관련 정보(사용자 ID, 권한 등)를 JSON 형태로 만든다(Payload).
  2. JSON 형태의 Payload를 base64 인코딩을 해서 문자열을 만들고, 미리 정한 시스템의  SecretKey(전체 시스템에서 사용하는 암호라고 이해하면 됨)를 이용하여 서명 문자열을 생성한다.
  3. Header정보, 인증정보(Payload), 서명 문자열을 하나의 문자열로 합친 후 클라이언트로 전송한다.
  4. 서버는 인증 요청에 대한 응답으로 이 인코딩된 문자열을 클라이언트로 전달한다.
  5. 클라이언트는 서버로부터 받은 토큰을 클라이언트의 저장공간(브라우저의 경우 쿠키나 브라우저내 로컬 스토리지 등)에 저장한다.
  6. 클라이언트는 매번 요청 시 이 토큰을 서버로 같이 전달한다.
  7. 서버는 클라이언트의 요청에서 받은 토큰 값을 이용하여 어떤 사용자의 요청인지 등을 확인한다.

JWT의 가장 큰 특징은 토큰 자체 내에서 이미 인증 관련 정보를 내장(self-contained)하고 있어 서버들 사이에 이 정보를 공유할 필요 없이 이 토큰을 받은 서버에서 토큰 정보만을 이용하여 인증을 처리할 수 있다는 것입니다. 이 특징 때문에 다른 몇가지 단점이 있음에도 불구하고 마이크로 서비스 기반(또는 여러 언어들이 동시에 사용되는 시스템)의 시스템에서는 많은 관심을 받고 있습니다

 

기존의 세션인증방식은 인증 관련 정보를 세션 저장소라는 DB에 저장했기 때문에 서버가 과부하 되거나 서버를 확장하기 어려웠다. 이를 보완하기 위해( = 서버자원을 절약) 사용자 인증에 필요한 정보를 토큰 자체에 담고 있어 별도 저장소에 정보를 저장해 둘 필요가 없는 JWT을 사용하게 되었다.

 

토큰은 로그인 이후 서버가 만들어주는 문자열이고, 문자열 안에는 사용자의 로그인 정보와 서버의 서명이 들어있다. 사용자가 로그인을 하면 서버는 사용자에 토큰을 발급하고, 사용자는 토큰과 함께 다른 API 작업을 요청한다. 서버는 토큰의 유효성 검사를 통해 요청한 것에 대한 응답을 해준다.

 

JWT의 한계로 어느 정도 규모가 있는 서비스에서 사용자 인증 용도로 JWT를 사용하기에는 부족한 경우가 있다는 점이 있다. 현재 로그인된 사용자의 모든 장비들을 나열해주거나, 특정 장비에서 로그아웃을 허용하는 기능을 구현하려면 서버 단에 사용자 세션을 저장하지 않고는 어렵다. 또, 단 한번 발급된 토큰은 수정 및 폐기가 불가하다는 단점이 있고 그렇기 때문에 유효기간을 짧게 지정해주는 것이 중요하다.

 

서명이 되어 있는 JWT 토큰 서버에서만 유효성을 검증할 수 있지만 그 안에 저장된 데이터는 누구나 쉽게 열람이 가능하다. 따라서 민감한 사용자 정보를 JWT 토큰에 그대로 저장하게 되면 큰 보안 문제로 이어질 수 있어서 각별한 주의가 필요하다. 가급적 JWT 토큰에는 사용자를 식별할 수 있는 아이디 정도만 저장하는 것이 좋으며 해당 사용자에 대한 추가 정보가 필요한 경우에는 서버에서 사용자 DB를 조회하는 것이 안전하다. 불가피한 이유로 JWT 토큰에 민감한 사용자 정보를 저장해야한다면 반드시 암호화를 하여 JWT 토큰을 디코딩한 후에도 알아볼 수 없게 해야한다.


JWT의 Access Token / Refresh Token

JWT도 제 3자에게 토큰 탈취의 위험성이 있기 때문에, 그대로 사용하는것이 아닌 Access Token, Refresh Token 으로 이중으로 나누어 인증을 하는 방식을 현업에선 취한다.

 

Access Token 과 Refresh Token은 둘다 똑같은 JWT이다. 다만 토큰이 어디에 저장되고 관리되느냐에 따른 사용 차이일 뿐이다.

  • Access Token : 클라이언트가 갖고있는 실제로 유저의 정보가 담긴 토큰으로, 클라이언트에서 요청이 오면 서버에서 해당 토큰에 있는 정보를 활용하여 사용자 정보에 맞게 응답을 진행
  • Refresh Token: 새로운 Access Token을 발급해주기 위해 사용하는 토큰으로 짧은 수명을 가지는 Access Token에게 새로운 토큰을 발급해주기 위해 사용. 해당 토큰은 보통 데이터베이스에 유저 정보와 같이 기록.

정리하자면, Access Token은 접근에 관여하는 토큰, Refresh Token은 재발급에 관여하는 토큰의 역할로 사용되는 JWT 이라고 말할 수 있다.

JWT 인증 방식을 만약 Access Token 만을 이용하면, Access Token은 발급된 이후 서버에 저장되지 않고 클라이언트에 저장되어 토큰 자체로 검증을 하며 사용자 권한 인증을 진행하기 때문에, Access Token이 탈취되면 토큰이 만료되기 전 까지, 토큰을 획득한 사람은 누구나 권한 접근이 가능해지는 문제점이 있었다.

그래서 토큰의 유효 시간을 부여하여 탈취 문제에 대해 대응을 하기도 하지만, 만일 유효 기간이 짧을 경우 그만큼 사용자는 로그인을 자주해야 하는 번거로움이 있다.

따라서 이러한 문제를 해결하기 위해 Refresh Token 이라는 추가적인 토큰을 활용하여 토큰을 이중 장막을 쳐서 보다 보안을 강화하는 식으로 보면 된다.

서버 세션 인증 방식과 JWT 인증의 차이

 

서버(세션) 기반 인증 시스템
서버의 세션을 사용해 사용자 인증을 하는 방법으로 서버측(서버 램 or 데이터베이스)에서 사용자의 인증정보를 관리하는 것을 의미한다.그러다 보니, 클라이언트로부터 요청을 받으면 클라이언트의 상태를 계속에서 유지해놓고 사용한다.(Stateful) 이는 사용자가 증가함에 따라 성능의 문제를 일으킬 수 있으며 확장성이 어렵다는 단점을 지닌다.

토큰 기반 인증 시스템
이러한 단점을 극복하기 위해서 "토큰 기반 인증 시스템"이 나타났다.
인증받은 사용자에게 토큰을 발급하고, 로그인이 필요한 작업일 경우 헤더에 토큰을 함께 보내 인증받은 사용자인지 확인한다.
이는 서버 기반 인증 시스템과 달리 상태를 유지하지 않으므로 Stateless 한 특징을 가지고 있다


구분 서버 세션방식 JWT 방식
인증정보 보관 장소 서버측에 보관 Token에 포함시키고 이를 클라이언트가 보관
인증된 정보 노출 여부 노출되지 않음 노출되어 있음
인증 정보의 무효화 방법 비교적 쉽게 무효화 가능 다소 복잡한 로직을 구현해야 가능
타임아웃 처리 방식 사용자가 요청을 보내면 타임아웃 시간이 계속 연장됨 한번 발급된 토큰의 타임아웃 시간은 연장할 수 없음. 재발급 필요

출처

Comments