Posts React 사용 시 JWT를 어디에 저장해야할까?
Post
Cancel

React 사용 시 JWT를 어디에 저장해야할까?

개요

  • 예전에 React를 처음 사용할 때 backend를 jwt 인증방식으로 구현한 뒤
    frontend에서는 이 jwt를 어디에 저장할지 고민했었다.
  • 그때 4장. JWT 이해 및 적용를 보고
    쿠키에 httpOnly 설정으로 저장하는 방법을 사용하기로 결정했다.
  • 당시는 따라하는데 급급하여 무작정 똑같이 하였는데,
    이번에 gonic-gin CORS 처리, CORS를 이용한 XSS 공격실험를 통해
    쿠키에 저장하는 방법에 대한 작은 확신이 가졌으며
    앞으로도 위와 같은 방법으로 구현해도 괜찮겠다는 생각이 들었다.

JWT 저장 1. REDUX에 저장

  • React에 대한 이해도가 거의 없을 때에는 redux에 JWT를 저장하는 방식을 생각하였다.
  • 하지만 redux는 새로고침 시 저장소가 초기화되므로 적합하지 않다.

JWT 저장 2. redux-persist를 이용하여 저장

  • 그럼 redux-persist를 이용하여 redux의 휘발성을 줄이는 방식을 써보는 것은 어떨까?
  • 하지만 redux-persist는 localstorage에 저장하므로 다음과 같은 이슈가 발생한다.

JWT 저장 3. localstorage에 저장

  • localstorage는 각각 출처(Origin)에 대해 독립적인 저장 공간을 제공한다(Web Storage 개념과 사용법).
  • 즉 브라우저에서 다른 페이지에 접속 시 우리 서비스에서 저장한 JWT를 열람할 수 없다.
  • 하지만 결국 javascript code로 localstorage에 저장된 값을 열람할 수 있다는 사실은 변하지 않는다.
  • 따라서 XSS 공격을 받을 시 javascript code로 JWT을 열람할 수 있는 이슈가 있다.

JWT 저장 4. Cookie에 httpOnly 설정을 하고 저장

  • Cookie에서 httpOnly 설정을 한 경우 javascript code로 해당 쿠키를 열람할 수 없다.
  • 따라서 XSS 공격에 localstorage보다 안전하다.
  • 하지만 Cookie에 JWT를 저장하면 매 요청마다 해당 쿠키가 같이 전송된다는 위험이 있다.
  • 이는 CSRF 공격에 취약하다는 이야기다.
  • CRSF(교차 사이트 요청 위조)(참고)
    • Cross-Site Request Forgery (CSRF) is a type of attack that occurs
      when a malicious web site, email, blog, instant message, or
      program causes a user’s web browser to perform an unwanted action
      on a trusted site when the user is authenticated.
    • 브라우저에서 우리 서비스에 로그인 한 상태라면
      인증정보가 담긴 JWT가 쿠키(httpOnly 설정)로 저장된다.
    • 이 상태에서 사용자가 피싱 메일 열람 등을 통해 우리 서비스로 아래와 같은 작업을 하면 작동한다.
      • 서비스 탈퇴 요청
      • 사용자 정보 조회
    • 왜냐하면 우리 서비스 서버는 이 요청이 사용자가 직접 보낸 요청인지,
      피싱에 의한 요청인지 알 수 없기 때문이다.
  • 하지만 CRSF는 XSS보다 대응할 수 있다.
    • 참고
    • Referer 체크
      • Referer 요청 헤더는 현재 요청을 보낸 페이지의 절대 혹은 부분 주소를 포함한다(참고)
      • Referer를 확인하여 해당 요청이 우리 서비스에서 온 것인지, 피싱 요청인지 확인할 수 있다.
      • 하지만 Referer 역시 요청 단에서 조작이 가능하다.
    • Double Submit Cookie 체크
      • 우리 서비스에서는 전송할때마다 임의의 난수 쿠키를 할당하고 요청 시 해당 난수를 따로 헤더에 등록하여 전송한다.
      • 쿠키의 동일출처정책 때문에 서버에서 요청을 받을 때
        우리 서비스의 요청에서는 난수 등록 쿠키가 조회되지만
        피싱 요청의 경우 난수 등록 쿠키가 조회되지 않을 것이다.
      • 따라서 서버 단에서는 요청의 난수 등록 쿠키와 난수 등록 헤더를 불러와 동일 여부만 확인한다.

결론

  • 프론트에서는 JWT를 httpOnly 설정하고 Cookie에 저장하는 방법이 가장 안전한 것 같다.
  • CRSF 문제가 생길 수 있으므로 Referer 체크와 Double Submit Cookie 체크를
    백엔드에서 구현하여 대비한다.

참고

This post is licensed under CC BY 4.0 by the author.