본문 바로가기
기타

JWT(Json Web Token)

by 왜안돼요 2023. 12. 14.
728x90
JWT는 당사자 간의 비밀을 제공하기 위해 암호화 될 수 있지만 서명된 토큰에 초점을 맞출 것이다. 서명된 토큰은 그 안에 포함된 클레임의 무결성을 확인할 수 있으며 암호화된 토큰은 다른 당사자의 클레임을 숨긴다. 공개/ 개인 키 쌍을 사용하여 토큰에 서명할 때 서명은 개인 키를 보유한 당사자만이 서명한 당사자임을 인증한다.

 

JWT

JWT는 Json Web Token의 약자로 데이터가 json으로 이루어져 있는 토큰을 의미한다. 두 개체가 서로 안전하게 정보를 주고 받을 수 있도록 웹 표준으로 정의된 기술이다.

 

구성요소

JWT는 각각의 구성요소가 점(.)으로 구분이 되어있으며 구성 요소는 다음과 같다.

  • header
  • Payload
  • Signature

header . payload . signature

 

Header

{
	"typ": "JWT",
    	"alg": "HS512"
        "kid": "서명 시 사용하는 키를 식별하는 값"
}

header에는 보통 토큰 타입이나, 서명 생성에 어떤 알고리즘이 사용되었는지 저장한다. 지금 같은 경우에는 현재 토큰의 타입이 JWT이고, 개인키로 HS512 알고리즘이 적용되어 암호화가 되어있다고 확인 할 수 있다.

(jwt를 어떻게 검증하는지에 대한 내용이 들어감. 해시 알고리즘의 이름을 적어줄 수 있음)

Payload

{
	"sub" : "1",
    	"iss" : "ori",
    	"exp" : 163698718,
    	"iat" : 163698718
}

payload에는 보통 Claim이라는 사용자에 대한, 혹은 토큰에 대한 property를 key-value의 형태로 저장한다. Claim이라는 말 그대로 토큰에서 사용할 정보의 조각인 셈이다. 어떤 Claim값을 넣는지는 개발자의 마음이지만 배울때는 JWT의 표준 스펙을 알아보자.

 

(토큰에 담아서 우리가 보내고자 하는 데이터가 담겨 있다. 이 정보의 조각은 Claim이라고 하고 , key-value의 한쌍으로 이루어져 있다. payload에는 여러 개의 클레임을 담을 수 있고, 클레임을 공개(Public) 혹은 비공개(private)할 것인지 등록(registered)할 것인지 결정할 수 있다.)

 

표준 스펙상 key의 이름은 세글자로 되어있다. JWT의 핵심목표는 사용자에 대한, 토큰에 대한 표현을 압축하는 것이기 때문에 이를 정의한 것이라 볼 수 있다.

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

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

 

Access token과 Refresh Token을 구분하고 시다면 "token_type"이라는 커스텀한 claim을 만들고 값을 아래와 같이 access token으로 두어 구분지어도 괜찮음

 

{
	"token_type" : "access token"
}

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

 

jwt.io에서 서버에서 생성한 jw를 넣기만 해도 볼 수 있는 화면이다. jwt에서 header와 Payload는 특별한 암호화 없이 흔히 사용할 수 있는 base64 인코딩을 사용하기 때문에 서버가 아니더라도 그 값들을 확인할 수 있다.

그래서 jwt는 단순히 식별하기 위한 정보만을 담아두어야 하는 것이다.

 

생성된 jwt는 왼쪽의 encoded된 값 처럼 점(.)을 구분자로 헤더, 페이로드, 시그니쳐로 나눠서 전달하게 되고, 서버는 헤더의 alg,kid 속성과 공개 키를 이용해 검증할 수 있다.

검증이 성공하면 페이로드의 값으로 접근을 해서 사용할 수 있는것이다.

 

Signature

header와 payload를 보여줄 때는 인코딩 되어 있던 값들을 jwt에 담겨있는 것처럼 디코딩된 상태를 사용한다. header를 디코딩한 값, Payload를 디코딩한 값을 위처럼 합치고 이를 your-512-bit-secret 서버가 가지고 있는 개인키를 가지고 암호화 되어있는 상태이다.

따라서 signature는 서버에 있는 개인키로만 암호화를 풀 수 있으므로 다른 클라이언트는 임의로 signature를 복호화할 수 없다.

 

(시그니처에는 위의 헤더와 페이로드를 합친 문자열을 서명한 값이다. 서명은 alg에 정의된 알고리즘과 secret key를 이용해 생성하고 Base64 URL-Safe로 인코딩한다. secret key를 포함해서 암호화가 되어있음)

 

 

공개 키(public key)와 비밀 키(secret key)

jwt에서는 기본적으로 공개 키 암호방식 (PKC, Public Key Cyptograpyh)를 사용하는데, 비대칭 암호방식을 이용해 공개 키와 비밀 키를 생성하고 이 키들을 상황에 따라 나누어 가지고 통신한다.

서명은 비밀 키가 있는 곳에서만 할 수 있고 공개 키를 가진 어느 곳에서나 이 데이터의 서명을 검증할 수 있다.

 

공개 키를 가진 누구나 데이터를 암호화해서 데이터를 보낼 수 있지만,

비밀 키를 가진 곳에서만 데이터를 복호화해서 내용을 확인할 수 있다.

 

비대칭 암호방식이기 떄문에

❌비밀 키로 암호화한 데이터는 다시 비밀 키로 풀 수 없고,

❌공개 키로 암호화한 데이터는 다시 공개 키로 풀 수 없다.

 

서명 : 비밀 키를 가진 극소수(주로 한명)만 데이터에 서명할 수 있다. 공개 키를 가진 아무나 데이터의 서명을 검증할 수 있다.
암호화: 공개 키를 가진 아무나 데이터를 암호화 할 수 있다. 비밀 키를 가진 극소수만 데이터를 복호화해 확인할 수 있다.

 

JWT의 장단점

장점

  1. 세션 방식과 다르게 별도의 인증 저장소가 필요 없어서 서버와의 커뮤니케이션 최소화
  2. 트래픽에 대한 부담이 적음
  3. 세션과 다르게 독립적인 느낌의 JWT를 활용한다

단점

  1. Jwt의 크기가 커질수록 거의 모든 요청에 대해 전송되므로 데이터 트래픽 크기에 영향을 미칠 수 있다.
  2. 토큰은 클라이언트에 저장되기 때문에 DB에서 사용자 정보를 수정하더라도 토큰에 직접 적용할 수 없다.

 

세션 기반 인증과 토큰 기반 인증 차이

사용자의 로그인 상태를 서버에서 처리하는 데 사용할 수 있는 대표적인 두 가지 인증 방식이 있다. 하나는 세션을 기반으로 인증하는 것이고, 다른 하나는 토큰을 기반으로 인증하는 것이다. 

 

세션 기반 인증 시스템

세션을 기반으로 인증 시스템을 만든다는 것은 서버가 사용자가 로그인 중임을 기억하고 있다는 뜻이다.

 

세션 기반 인증 시스템에서 사용자가 로그인을 하면, 서버는 세션 저장소에 사용자의 정보를 조회하고 세션 id를 발급한다. 발급된 id는 주로 브라우저의 쿠키에 저장한다. 그다음에 사용자가 다른 요청을 보낼 때마다 서버는 세션 저장소에서 세션을 조회한 후 로그인 여부를 결정하여 작업을 처리하고 응답을 한다. 세션 저장소는 주로 메모리, 디스크, 데이터베이스등을 사용한다.

 

세션 기반 인증 단점

서버를 확장하기가 번거로워질 수 있다는 점이다. 만약 서버의 인스턴스가 여러 개가 된다면, 모든 서버끼리 같은 세션을 공유해야 하므로 세션 전용 데이터베이스를 만들어야 할 뿐 아니라 신경 써야 할 것도 많다.

세션 기반 인증이 무조건 좋지 않은 것이 아니라 잘 설계하면 충분히 좋은 시스템이 될 수 있다.

 

토큰 기반 인증 시스템

토큰은 로그인 이후 서버가 만들어주는 문자열이다. 해당 문자열 안에는 사용자의 로그인 정보가 들어 있고, 해당 정보가 서버에서 발급 되었음을 증명하는 서명이 들어 있다. 

서명 데이터는 해싱 알고리즘을 통해 만들어지는데, 주로 HMAC SHA256 혹은 RSA SHA256 알고리즘이 사용된다.

 

서버에서 만들어 준 토큰은 서명이 있기 때문에 무결성이 보장된다. 무결성이란 정보가 변경되거나 위조되지 않았음을 의미하는 성질이다. 사용자가 로그인을 하면 서버에서 사용자에게 해당 사용자의 정보를 지니고 있는 토큰을 발급해주고, 추후 사용자가 다른 API를 요청하게 될 때 발급받은 토큰과 함께 요청하게 된다. 그러면 서버는 해당 토큰이 유효한지 검사하고, 결과에 따라 작업을 처리하고 응답한다.

 

JWT 프로세스

Access Token

더 상세한 설명

 

 

  1. 사용자가 Id,pw를 입력하고 서버로 로그인 요청을 보낸다
  2. 서버는 비밀키를 통해서 서명을 하고 공개키로 암호화 시킨 access token을 발급한다
  3. access token을 사용자(클라이언트)에게 보낸다
    여기까지하면 사용자는 로그인이 된것
  4. 로그인 정보가 필요한 api call 마다 토큰을 실어서 보낸다
    사용자(클라이언트)는 api를 요청할 때 authorization heade에 access token을 담아서 보낸다
  5. 서버에서는 사용자가 보낸 토큰을 공캐 키로 서명을 체크하고, 안에 담긴 정보를 확인한다.
    서버는 secret key로 사용자가 보낸 토큰의 서명을 복호화 하여서 유효한 토큰인지 확인한다.
  6. 서버가 요청에 대한 응답을 사용자(클라이언트)에게 전달한다.

Refresh Token

acess token만을 사용했을 때 보안 문제를 해결하기 위해 나온 Refresh token

 

위와 같은 방식으로 진행했을 때의 문제점은 acess token을 탈취 당했을 때이다. 유효기간이 긴 토큰이라면, 그 시간동안 정보를 탈취당하게 되고 또 유효기간을 줄이자니 사용자가 로그인을 여러 번 해야하는 번거로움이 있다.

그래서 나온것이 Refresh Token이다

 

refresh token 또한 access token과 같은 Jwt이다.

로그인 했을 떄 서버에서 access token, refresh token을 동시에 보내준다. 

단, 둘의 유효기간을 다르게 해서 보낸다.

 

Refresh token을 한 달, access token을 하루로 잡았다면 access token의 기간이 다 되어도  Refresh token의 기간이 남아 있기 때문에 사용자는 로그인 없이 다시 access token을 발급 받을 수 있다 (로그인 유지)

refresh token은 access token을 다시 발급 받기 위한 jwt 이다.

 

 

토큰을 유지하는 위치

토큰을 유지하는 방법에는 다양한 브라우저 저장소가 있다.

secure httpOnly 쿠키, 로컬스토리지, 쿠키와 같이 다양한데 이것은 개발자의 취향과 장단점이 서로 다르다.

 

🍪 프론트에서 안전하게 로그인 처리하기 (ft. React)

localStorage냐 쿠키냐 그것이 문제로다

velog.io

참고하깅

 

localstorage

공격자가 클라이언트 브라우저에 스크립트를 삽입해 공격하는 XSS(Cross-site scripting)에 취약하다

 

Cookie

🍪쿠키가 뭔데??

XSS(Cross-site scripting) & CSRF(Cross-site request forgery): 다른 도메인에서 우리 도메인으로 api call을 날리는 공격

둘 다에 취약해질 수 있다.

 

secure httpOnly 역시 CRSF 공격에 취약하다.

 

 

 

마무리

프로젝트 진행하면서 항상 로그인을 맡아서 진행했었는데 어어 ~ 리액트는 jwt로 해야돼~ 뭐 그렇대! 하고 대충 넘어갔었는데

정리하면서 여러 블로그도 보고 공식 문서도 보니까 왜 이렇게 사용되는지 알것같다

refresh token도 그냥 다시 토큰 재발급 해주는거아냐? 하고 넘어갔는데 좀 더 알 수있게 됐음

 

 

 

출처

리액트 다루는 기술

 

JWT(Json Web Token) 알아가기

jwt가 생겨난 이유부터 jwt의 실제 구조까지 | 사실 꾸준히 작성하고 싶었던 글이지만 JWT를 제대로 개념을 정리하고 구현을 진행해본 적이 없었는데 리얼월드 프로젝트를 진행하면서 JWT에 대한

brunch.co.kr

 

 

🤔 JWT, 정확하게 무엇이고 왜 쓰이는 걸까?

Json Web Token에 대해서 정확히 알고 넘어가자.

velog.io

 

최근댓글

최근글

skin by © 2024 ttuttak