JWT

강정우·2023년 5월 30일
0

네트워크

목록 보기
8/32
post-thumbnail

특징

  1. 모든 데이터를 내장하고 있다.

  2. 머리(header) 가슴(payload) 배(signature) 로 구성되어있다.

  3. 서버를 Stateless하게 돌릴 수 있다. => 확장성 증대

  • Header : type(typ), algorithm(alg)의 속성값을 갖는다.
    • 토큰 타입 지정
    • 해싱 알고리즘 지정 (HMAC SHA256, RSA 가 주로 쓰임)

Payload

  • Payload : 정보의 단위인 "클래임" 이 들어가고 이는 크게 3가지로 나뉜다.

  • Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다. (패스워드 등)

registered Claim

  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰의 만료시간 (expiraton), NumericDate 형식이며 언제나 현재 시간보다 이후로 설정되어있어야한다.
  • nbf: Not Before 를 의미하며, 토큰의 활성화 날짜라고 생각하면 편하다. NumericDate 형식
  • iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있다.
  • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용하다.

public Claim

  • 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 하며 클레임 이름을 URI 형식으로 짓는다.

private Claim

  • 클라이언트 <->서버 협의하에 사용되는 클레임 이름이다.
  • 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야한다.

Singnature

  • 헤더의 인코딩값과, 정보의 인코딩값을 합친후 주어진 비밀키로 해쉬를 하여 생성한다.

  • base64 URL-safe encoding을 해줄 필요가 있다. 프론트가 쓰기 편하도록 말이다.

  • 여기 서명부에는 비대칭 알고리즘을 사용하므로 암호화를 위한 키와 복호화를 위한 키가 다르다.
    암호화(서명)에는 개인키를 복호화(검증)에는 공개키를 사용한다.

동작 (font-end)

  • 사용자가 로그인하면 JSON Web Token이 반환된다.
    토큰은 자격 증명이므로 보안 문제를 방지하기 위해 세심한 주의를 기울여야 한다.

  • 또한 보안이 취약하기 때문에 민감한 세션 데이터를 브라우저 저장소에 저장해서는 안된다.

  • 사용자가 보호된 경로 또는 리소스에 액세스하려고 할 때마다 사용자 에이전트는 일반적으로 Bearer 스키마를 사용하여 Authorization 헤더에서 JWT를 보내야 한다. Header의 내용은 다음과 같아야 한다.

only fetch API

const token = 'your_jwt_token'; // JWT 토큰 값

fetch('https://api.example.com/data', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
})
  .then(response => {
    // 응답 처리
  })
  .catch(error => {
    // 에러 처리
  });

with axios, async

import axios from 'axios';

const fetchData = async () => {
  const token = 'your_jwt_token'; // JWT 토큰 값

  try {
    const response = await axios.get('https://api.example.com/data', {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });

    // 응답 처리
    console.log(response.data);
  } catch (error) {
    // 에러 처리
    console.error(error);
  }
};

fetchData();
  • 이는 특정 경우에 stateless(상태 비저장) Authorization 매커니즘일 수 있다.
    서버의 보호된 경로가 Authorization header(인증헤더)에서 유효한 JWT를 확인하고, 유효한 JWT가 있는 경우 사용자는 보호된 리소스에 액세스할 수있다.
    JWT에 필요한 데이터가 포함되어 있는 경우, 데이터베이스를 조회하여 특정 작업을 수행할 필요가 줄어들 수 있지만, 모든 경우가 그런 것은 아니다.

  • 토큰이 Authorization header(인증헤더)에서 전송되는 경우 CORS(Cross-Origin Resource Sharing)는 쿠키를 사용하지 않으므로 문제가 되지 않는다.

단점

  • JWT는 토큰의 길이가 길어, 인증 요청이 많을수록 네트워크 부하가 심해진다.
  • 토큰을 탈취당하면 대처하기 어렵다. 토큰은 한 번 발급되면 유효기간이 만료될 때까지 계속 사용이 가능하다.
  • 특정 사용자의 접속을 강제로 만료하기 어렵다. (쿠키/세션 기반 인증은 서버 단에서 쉽게 삭제할 수 있지만 토큰은 그게 안 됨)

Sliding Session

서비스를 지속적으로 이용하는 클라이언트에게 자동으로 토큰 만료 기한을 늘려주는 방법이다
만약 글을 작성하다가 토큰이 만료된다면 새로운 토큰을 발급해주는 것이다.
사용자가 로그인을 자주 할 필요가 없다.

Refresh Token

클라이언트가 로그인할 때 Access Token 및 Refresh Token을 발급해주는 방법이다.
Refresh Token은 Access Token보다 만료 기한이 긴 토큰이다.
클라이언트가 요청을 보냈는데 Access Token이 만료되었을 때, Refresh Token을 이용하여 Access Token의 재발급을 요청한다.

이때 서버는 DB에 저장된 Refresh Token과 비교하여 유효하면 Access Token을 발급한다.
만약 Refresh Token도 만료된 경우라면 사용자에게 로그인을 요구한다.

이 전략을 사용하면 Access Token의 만료 기한을 짧게 설정하여 위의 짧은 만료 기한 설정 전략처럼 탈취되더라도 빠르게 만료될 수 있다. 또한 짧은 만료 기한에도 불구하고 자주 로그인을 할 필요가 없어진다. 서버가 강제로 Refresh Token을 만료시킬 수도 있다.

하지만 이렇게 완벽하게 보이는 Refresh Token 발급 방법도 단점은 있다. Refresh Token 검증을 위해 DB(혹은 별도의 저장소)에 저장해야 하고, 자원이 소요될 뿐더러 추가적인 I/O 작업이 발생한다. (JWT의 장점은 I/O 작업이 필요없는 빠른 인증 처리였다.)

reference

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글