codingBird

TIL - 그럼 JWT을 어떻게 보관해야 가장 안전할까? 본문

TIL

TIL - 그럼 JWT을 어떻게 보관해야 가장 안전할까?

김뚜루 2022. 11. 23. 22:47

전성기 시절 마이클 타이슨 아래턱에 보관한다.

앞서 작성한 TIL에서 말했다시피 JWT를 Cookie에 저장하든 localStorage에 저장하든 탈취에 취약한 상황은 존재한다. 그럼 되도록 안전하게 보관하려면 어떻게 해야 할까?

먼저 Cookie와 localStorage를 비교해보자.

  • localStorage와 Cookies 둘 다 XSS 공격에 취약하지만 httpOnly Cookies 사용하면 Cookies는 localStorage에 비해 공격하기 힘들어져 비교적 안전해진다
  • Cookies는 CSRF 공격(CrossSite Request Forgery - 사용자가 의도치 않은 요청을 서버에 보내게 하는 것)에 취약하지만, sameSite flag와 anti-CSRF tokens을 이용해 보완할 수 있다.
  • OWASP에서는 스크립트가 편하게 접근할 수 있는 localStorage에 결코 session identifier를 localStorage에 저장하지 않는 것을 추천한다. → Authorization: Bearer을 사용해야 하는 경우 JWT 크기가 4KB 제한을 넘기더라도 Cookies에 저장하는 방법은 있다.

비교해본 결과로 localStorage보다는 Cookies가 조금 더 안전해 보인다. 그럼 쿠키를 이용해 JWT를 저장한다면 어떤 방식으로 저장해야 가장 안전하다고 할 수 있을까?

인터넷을 찾아본 결과 Access token을 메모리에 저장하고 refresh token을 Cookies에 저장하면 된다고 한다. 방법은 아래와 같다.

1. 유저 인증을 할 때 Access Token과 Refresh Token을 반환한다.

Access_token은 response body에 포함되고, refresh_token은 쿠키에 포함된다.

Refresh Token은 아래와 같이 설정된다

  • httpOnly → 스크립트를 통한 접근을 제한한다
  • secure-true → HTTPS를 통해서만 보내지도록 설정한다
  • SameSite=strict → 크로스 사이트 요청에는 항상 전송되지 않도록 해서 CSRF를 예방할 수 있다.

2. Access Token을 메모리에 저장한다.

Access Token을 프론트 단의 변수에 저장한다.

문제는 이렇게 하면 브라우저에서 탭 전환이나 새로고침을 하면 access token이 사라지는데 이 문제를 해결하기 위해 Refresh Token이 존재한다.

3. Refresh Token을 이용해 새로운 Access Token을 발급 받는다.

Access Token이 사라지거나 만료되었을 때 Response의 Cookies에 있던 Refresh Cookies를 포함한 Request가 서버 /refresh_token의 endpoint를 hit하게 되고, API Request에 사용할 수 있는 새로운 Access Token을 발급받게 된다.

이렇게 함으로서 Cookies를 이용하더라도 4KB가 넘는 토큰을 인증에 사용할 수 있는 것이다!

명심하자

  • localStorage는 스크립트 접근으로 부터 자유롭지 못하다
  • Cookies 또한 그냥 사용하게 되면 탈취 위험이 높다
  • httpOnly, sameSite, secure=true는 가장 손쉽게 보안 등급을 높일 수 있는 방법이다.