본문 바로가기

Web

JWT(JSON Web Token)

JWT(JSON Web Token)

  • 웹 애플리케이션의 인증과 권한 부여에 널리 사용되는 방식

JWT 의 기본 구조

Header

{
"alg": "HS256", // 서명 암호화 알고리즘
"typ": "JWT" // 토큰의 타입
}
  • 토큰의 타입과 사용된 암호와 알고리즘을 지정

Payload

  • claim 이라 불리는 토큰에 담을 정보가 들어감
Registered Claim Public Claims Private Claims
미리 정의된 클레임(권장되는 클레임 집합)
iss(발급자)/sub(제목)/exp(만료시간) 등
사용자 정의 클레임으로, 공개적으로 정의 당사자들 간에 정보를 공유하기 위해 생성된 맞춤 클레임

 

Signature

  • 헤더와 페이로드를 검증하기 위해 사용

Header, Payload, Signature 각 부분은 Base64URL로 인코딩되어 URL에서 안전하게 사용할 수 있는 문자열로 변환된다.

    (.으로 구분)

→ 이러한 JWT의 구조가 토큰 자체에 필요한 모든 정보를 포함하므로 별도의 저장소 없이 손쉽게 인증 정보를 전달하고 검증할 수 있다.

 

쿠키, 세션, 토큰

쿠키 (Cookie)

  • 클라이언트 브라우저에 저장되는 작은 텍스트 파일
  • key-value 형태로 데이터 저장
  • 서버가 클라이언트에 데이터를 저장하기 위한 수단

세션 (Session)

  • 서버 측에서 관리하는 사용자 인증 정보
  • 서버의 메모리나 DB 에 저장
  • 클라이언트는 세션 ID 만 보유
  • 세션 ID 는 보통 쿠키를 통해 클라이언트에 전달된다.

토큰 (Token)

  • 클라이언트가 서버에 인증정보를 증명하기 위해 전송하는 암호화된 문자열
  • JWT 는 자체적으로 필요한 정보를 포함하고 있어
  • 서버에서 별도 저장소 없이 검증이 가능하다.(stateless 한 인증 방식 제공)

 

Access Token & Refresh Token

  • Access token과 Refresh token은 보안과 사용자 경험의 균형을 위해 존재한다.

Access Token

  • 사용자 인증 정보를 담고 있는 JWT
  • 실제 리소스에 접근할 때 사용되는 토큰
  • 비교적 짧은 유효 기간(보통 15분 ~ 2시간)을 가진다.
  • 탈취 피해를 최소화 하기 위해 짧은 유효기간이 설정된다.

Refresh Token

  • Access Token을 새로 발급받기 위한 토큰
  • 더 긴 유효 기간(보통 몇 주 ~ 1달)을 가진다.
  • Access token 이 만료되었을 때 새로운 Access token을 발급받는 용도
  • 사용자가 매번 로그인하지 않아도 되게 해준다.

 

토큰 갱신 프로세스

 

토큰 저장 위치와 안전성

Access Token

  • 메모리나 짧은 수명의 HttpOnly 쿠키에 저장하는 것이 안전하다.
  • 브라우저 메모리에 저장하면 XSS 공격에 취약할 수 있지만, 페이지 새로고침 시 손실된다

      * XSS 공격 :  XSS(Cross-Site Scripting) 공격자가 악성 스크립트를 웹 페이지에 삽입하여 사용자의 브라우저에서 실행되게 하는 공격

Refresh Token

  • HttpOnly, Secure 플래그가 설정된 쿠키에 저장하는 것이 가장 안전하다.
  • 서버 측 데이터베이스에도 저장하여 필요 시 폐기할 수 있게 해야한다.

 

토큰 관리 방법

1. localStorage/sessionStorage

// 저장
localStorage.setItem('accessToken', token);
// 조회
const token = localStorage.getItem('accessToken');
  • 장점 : 구현이 간단하고 영구 저장이 가능하다.
  • 단점 : XSS 공격에 취약해 보안상 위험이 있다.
  • JavaScript 로 접근이 가능하다.
  • Access Token 저장은 권장되지 않는다.

2. 메모리 단에서 관리 (Context API, Zustand, Tanstack Query)

// Context API
const AuthContext = createContext();

const AuthProvider = ({ children }) => {
  const [accessToken, setAccessToken] = useState(null);
  
  return (
    <AuthContext.Provider value={{ accessToken, setAccessToken }}>
      {children}
    </AuthContext.Provider>
  );
};
// Zustand
const useAuthStore = create((set) => ({
  accessToken: null,
  setAccessToken: (token) => set({ accessToken: token }),
}));
// TanStack Query
const { data: accessToken } = useQuery(['auth'], getAccessToken);
  • 장점 : XSS 공격으로 부터 상대적으로 안전하고, 컴포넌트 간 공유가 용이하다.
  • 단점 : 새로고침 시 상태가 초기화되어 데이터가 손실된다.
  • Access Token 저장에 적합하다.

3. 쿠키 (HttpOnly, Secure)

// 서버 측 설정
res.cookie('refreshToken', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict'
});
  • HttpOnly : JavaScript 접근 차단이 가능하고 XSS 공격으로부터 보호한다.
  • Secure : HTTPS 프로토콜에서만 쿠키를 전송하고 암호하된 통신만 허용한다.
  • Refresh Token 저장에 적합하다.

 

HttpOnly 와 Secure 옵션

옵션들을 사용하면 쿠키의 보안을 크게 향상시킬 수 있다.

HttpOnly는 클라이언트 측 스크립트의 쿠키 접근을 차단하고, Secure는 암호화된 연결을 통해서만 쿠키를 전송하도록 보장한다.

HttpOnly

  • JavaScript 를 통한 쿠키 접근을 방지한다.
  • XSS 공격으로부터 쿠키를 보호한다.

Secure

  • HTTPS 연결을 통해서만 쿠키가 전송되도록 한다.
  • 중간자 공격으로부터 보호한다.

 

권장되는 토큰 관리 전략

1. Access Token: 메모리 관리 (Context API, Zustand, TanStack Query 중 선택)

  • Access Token은 빈번히 사용되므로 메모리에서 빠른 접근이 가능하도록

2. Refresh Token: httpOnly 쿠키로 관리

  • Refresh Token은 보안이 중요하므로 httpOnly 쿠키로 안전하게 보관

3. 프로젝트 특성에 따라 관리

  • SPA: Context API나 Zustand 사용 권장
  • SSR: 쿠키 기반 관리 권장
  • 복잡한 상태 관리 필요: TanStack Query 고려

 

'Web' 카테고리의 다른 글

프론트엔드 에러 모니터링  (0) 2025.01.18
Unit Test(with Jest)  (0) 2025.01.18