jwt

JWT에 대한 이해 2-1 with JWT handbook

Chapter 2-1

Posted by 동식이 블로그 on December 11, 2019

JWT에 대한 이해 2-1

약 한달 만에 다시 시작하는 JWT Handbook 읽어보기…

영어라서 길다..어렵다…단어 하나하나 찾아보느라 시간이 엄청 걸린다…

2장이 긴 관계로 절반씩 나누어서 올린다

가장 문제인건 단어가 내포하고 있는 뜻을 이해하는 것..?


2. Practical Application

JWT의 자세한 구조에 대해 알아보기 앞서 몇개의 실용적인 사례들에 대해 알아보도록 하자. Chapter2는 오늘날 업계에서 사용되는 일반적인 JWT기반 솔루션의 복잡성(또는 단순성)에 대해 설명한다


2-1. Client-side / Stateless Session

Stateless

접속을 끊는 순간 클라이언트와 서버의 통신은 끝나고, 상태 정보는 유지되지 않는 특성

Stateless Session은 Client-side 데이터에 지나지 않는다. 이 애플리케이션의 핵심 측면은 세션의 내용을 인증하고 보호하기 위해 서명 및 암호화를 사용하는 것이다. Client-side 데이터는 변조될 수 있기 때문에 backend에서 조심스럽게 다뤄져야 한다

JWT는 JWT와 JWE의 힘으로 다양한 유형의 서명과 암호화를 제공할 수 있다. 서명은 변조로부터 데이터를 검증하는데 유용하고, 암호화는 데이터를 제3자가 읽지 못하도록 보호하는데 유용하다.

대부분의 time session은 서명만 하면 된다. 즉 그 안에 저장된 데이터를 제3자가 읽을 때 보안이나 프라이버시 우려가 없다.

일반적으로 제3자가 안전하게 읽을 수 있는 클레임의 일반적인 예는 하위 클레임이다. 하위 클레임은 일반적으로 상대방(사용자 ID 또는 이메일)중 한사람을 식별하기 위해 추가 클레임이 필요할 수 있다.

적절하게 개방되어 있지 않을 수 있는 클레임은 사용자의 쇼핑 카트를 나타내는 항목 클레임이 될 수 있다. 이 카트는 사용자가 구매하려는 항목으로 채워질 수 있으므로 session과 연관된다. 제3자(클라이언트측 스크립트)는 프라이버시 문제가 우려되는 암호화 되지않은 JWT를 가져올 수 있다.

1

2-1-1. Security Considerations

2-1-1-1. Signature Stripping

서명된 JWT를 공격하는 일반적인 방법은 서명을 제거하는 것이다. 서명된 JWT는 헤더, 페이로드, 서명의 세 부분으로 구성된다. 이 세 부분은 따로 인코딩 되어있기 때문에 서명을 제거한 후 헤더를 변경하여 JWT가 서명되지 않았다고 주장할 수 있다. 특정 JWT 유효성 검사 라이브러리를 부주의하게 사용하면 서명되지 않은 토큰을 유효한 토큰으로 간주하여 공격자가 자신의 재량에 따라 페이로드를 수정할 수 있다.

2

2-1-1-2. Cross-Site Request Forgery (CSRF)

CSRF공격은 사용자의 브라우저를 속여 다른 사이트에 요청을 전송함으로써 사용자가 로그인한 사이트에 대한 요청을 수행하려고 시도한다. 수명이 짧은 JWT가 이 경우에 도움이 된다. JWT(및 세션 데이터)가 쿠키로 저장되지 않으면 CSRF 공격이 불가능하게 된다.

3

2-1-1-3. Cross-Site Scripting (XSS)

XSS공격은 신뢰할 수 있는 사이트에 JavaScript를 주입하려고 시도한다. 주입된 JavaScript는 쿠키와 로컬 저장소에서 토큰을 훔칠 수 있다. 엑세스 토큰이 만료되기 전에 유출되면 악의적인 사용자가 보호된 리소스에 엑세스 하는 데 토큰을 사용할 수 있다. 이에 대한 대비는 백엔드로 전달되는 모든 데이터의 적절한 유효성 검사에 의존한다. 쿠키를 사용할 경우 HttpOnly flag를 설정하여 JavaScript에서 쿠키를 엑세스하지 못하도록 보호할 수 있다. HttpOnly flag는 유용하지만 CSRF공격으로부터 쿠키를 보호하지는 않는다.

Http Only flag란?

JavaScript의 document.cookie를 이용해서 쿠키에 접속하는 것을 막는 옵션. 쿠키를 훔쳐가는 행위를 막기위한 방법

4

2-1-2. Client-Side Session은 유용한가?

어떠한 접근법에도 장단점이 있으며, 클라이언트측 세션도 예외는 아니다. 어떤 애플리케이션은 큰 세션이 필요할 수 있다. 모든 요청(그룹)에 대해 이 상태를 앞 뒤로 전송하면 백엔드에서 대화 감소(reduced chattiness)의 이점을 쉽게 극복할 수 있다. 백엔드에서 클라이언트측 데이터와 데이터베이스 조회 간의 일정한 균형이 필요한데 이는 애플리케이션의 데이터 모델에 따라 달라진다.

2-1-3. Example

예시가 node.js로 구현되어 있어서 node.js로 한번 해봐야겠다…

쇼핑 애플리케이션으로 간단한 예를 들어보자. 유저의 쇼핑카트는 클라이언트측에 보관되는데, 이 예에서 JWT는 여러가지인데, 쇼핑카트는 그 중 하나가 된다.

  • ID 토큰용 JWT : UI에 유용한 사용자 프로필 정보를 전달하는 토큰
  • 백엔드 API와 상호작용하기 위한 JWT 토큰
  • 클라이언트 상태를 위한 JWT 토큰 : 쇼핑카트

쇼핑카트는 아래처럼 디코딩된다.

1
2
3
4
5
6
7
8
9
{
	"item" : [
		0,
		2,
		4
	],
    "iat": 1493139659,
    "exp": 1493143259
}

각각의 아이템들은 숫자 ID로 식별된다. 인코딩되고 서명된 JWT는 다음과 같다

1
2
3
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpdGVtcyI6WzAsMiw0XSwiaWF0IjoxNDkzMTM5NjU5LCJleHAiOjE0OTMxNDMyNTl9.
932ZxtZzy1qhLXs932hd04J58Ihbg5_g_rIrj-Z16Js

카트에 있는 항목을 렌더링하려면, 프론트에서는 쿠키에서 검색만 하면 된다

1
2
3
4
5
6
7
8
9
10
11
12
13
function populateCart() {
    const cartElem = $('#cart');
    cartElem.empty();
    const cartToken = Cookies.get('cart');
    if(!cartToken) {
    	return;
    }
    const cart = jwt_decode(cartToken).items;
    cart.forEach(itemId => {
        const name = items.find(item => item.id == itemId).name;
        cartElem.append(`<li>${name}</li>`);
    });
}

프론트는 서명에 대해 확인하지 않고, JWT를 간단히 디코딩해서 보여준다. 확인은 백엔드에서 하고, 모든 JWT는 확인된다.

생략…


JWT 공식사이트의 Sebastián E. Peyrott, Auth0 Inc. “The JWT Handbook.”을 요약 정리했습니다… 오역이 있을수 있으니 더 자세한 내용은 사이트를 참고해주세요…