개발

JWT(Json Web Token)란 무엇이고 어디에 담아야하는가

pizzaYami 2023. 9. 16.

프로젝트를 진행하면서 JWT를 로컬스토리지에 담아서 사용하다가 백엔드에서 쿠키에 담아서 사용하는 것을 제안을 하여서 자세히 알아보고자 블로깅을 한다.

 

1. JWT란

모바일이나 웹의 사용자 인증을 위해 사용하는 암호화된 토큰을 의미한다.

JWT 정보를 request에 담아 사용자의 정보 열람, 수정 등 개인적인 작업들을 수행할 수 있다.
그 중에서도 JWT는 웹 표준을 따르고 있으며, JSON 객체를 사용하여 정보를 전달합니다.

 

웹표준을 따르기 떄문에 대부분의 언어가 이를 지원한다.

 

2. 구조

헤더, 내용, 서명이 .(dot ;점)을 구분자로 하여 JWT 토큰 1개를 이룬다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

 

header : Algrorithm & token type

인코딩 : Base64

{
  "alg": "HS256",
  "typ": "JWT"
}

헤더에서는 해시 알고리즘과 토큰의 타입을 정의할 수 있습니다.
HS256은 HMAC SHA 256을 의미합니다.
해시 알고리즘 중 한 가지입니다.
타입의 값 JWT는 이 토큰을 JWT로 지정합니다.

 

payload : data

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

내용에서는 전달하는 데이터를 포함할 수 있습니다.
데이터 각각의 Key를 claim이라고 부릅니다.
claim은 사용자가 원하는 Key와 Value로 구성할 수 있습니다.
claim에는 3가지 종류가 있습니다.
registered, public, private

 

registered claim : 등록된 클레임

컴팩트하게 3글자로 정의하며, 필수는 아니나 사용이 권장됩니다. iss (issuer), exp (expiration time), sub (subject), aud (audience) 등이 있습니다. 그 외의 클레임 종류 : https://datatracker.ietf.org/doc/html/rfc7519#section-4.1

 

public claim : 공개 클레임

사용자가 자유롭게 정의할 수 있습니다. 단, 충돌을 방지하려면 IANA JSON 웹 토큰 레지스트리에 정의돼 있거나 충돌이 방지된 네임스페이스를 포함하는 URI로 정의해야 합니다. URI로 정의하는 경우 : {"http(s)://specific.uri/@unique_recommended_namespace/additional_path": true} IANA JSON Web Token Registries : https://www.iana.org/assignments/jwt/jwt.xhtml

 

private claim : 비공개 클레임

이는 등록된 또는 공개 클레임이 아닌 클레임이며, 정보를 공유하기 위해 만들어진 커스터마이징된 클레임입니다.

 

precautions : 주의 사항

Payload는 서명된 파트가 아닙니다. 단순 Base64 인코딩이 된 파트이며, 이는 누구나 디코딩하여 데이터 열람이 가능합니다. password 같은 결정적인 요소들은 Payload에 담기면 안 됩니다.

 

 

SIGNATURE

해시 : HMAC SHA 256

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

secret은 말 그대로 유저가 지정하는 비밀 코드입니다.
위와 같이 해싱하면 서명이 완성됩니다.

 

3. JWT 어디에 저장해?

보안 관련 대책 없이 JWT를 아무 곳에나 저장을 한다는 것은 우리 고객 정보는 가져가도 상관없다는 의미나 다름 없다.

대표적인 장소로는 localStorage와 cookie가 있다.

결론적으로는 둘 중 정답은 없으며 각각 장단점이 있다.

 

CSRF, XSS 과 관련된 설명은 레퍼런스 블로그를 보자.

localStorage에 저장

 

장점

CSRF 공격에는 안전하다.
그 이유는 자동으로 request에 담기는 쿠키와는 다르게
js 코드에 의해 헤더에 담기므로 XSS를 뚫지 않는 이상
공격자가 정상적인 사용자인 척 request를 보내기가 어렵다.

 

단점

XSS에 취약하다.
공격자가 localStorage에 접근하는 Js 코드 한 줄만 주입하면
localStorage를 공격자가 내 집처럼 드나들 수 있다.

 

cookie에 저장

 

 장점

XSS 공격으로부터 localStorage에 비해 안전하다.

쿠키의 httpOnly 옵션을 사용하면 Js에서 쿠키에 접근 자체가 불가능하다.
그래서 XSS 공격으로 쿠키 정보를 탈취할 수 없다.
(httpOnly 옵션은 서버에서 설정할 수 있음)

하지만 XSS 공격으로부터 완전히 안전한 것은 아니다.
httpOnly 옵션으로 쿠키의 내용을 볼 수 없다 해도
js로 request를 보낼 수 있으므로 자동으로 request에 실리는 쿠키의 특성 상
사용자의 컴퓨터에서 요청을 위조할 수 있기 때문.
공격자가 귀찮을 뿐이지 XSS가 뚫린다면 httpOnly cookie도 안전하진 않다.

 

단점

CSRF 공격에 취약하다.
자동으로 http request에 담아서 보내기 때문에
공격자가 request url만 안다면
사용자가 관련 link를 클릭하도록 유도하여 request를 위조하기 쉽다.

 

가장 좋은 방법

refresh token을 사용하는 방법이 있다.

백엔드 api 개발자와 소통이 가능하다면
refresh token을 httpOnly 쿠키로 설정하고
url이 새로고침 될 때마다 refresh token을 request에 담아
새로운 accessToken을 발급 받는다.
발급 받은 accessToken은 js private variable에 저장한다.

이런 방식을 사용하는 경우,
refresh token이 CSRF에 의해 사용된다 하더라도
공격자는 accessToken을 알 수 없다.

CSRF는 피해자의 컴퓨터를 제어할 수 있는 것이 아니기 때문이다.
요청을 위조하여 피해자가 의도하지 않은
서버 동작을 일으키는 공격방법이기 때문에
refresh token을 통해 받아온 response(accessToken)는
공격자가 확인할 수 없다.

따라서 쿠키를 사용하여 XSS를 막고
refresh token 방식을 이용하여 CSRF를 막을 수 있다.

 

레퍼런스

JWT는 어디에 저장해야할까? - localStorage vs cookie

 

'개발' 카테고리의 다른 글

node.js, NPM은 무엇인가  (1) 2023.11.28
이미지를 가져오는 여러가지 방법  (1) 2023.10.06
Atomic Design Pattern  (1) 2023.10.05
Mongo DB 왜 쓰는지와 셋팅방법  (0) 2023.09.06
서버통신하려면 ajax (axios)  (0) 2023.08.18

댓글