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

위범석·2022년 7월 6일
0

참고 : https://velog.io/@0307kwon/JWT%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-localStorage-vs-cookie

  1. JWT
    Json Web Token의 약자로 모바일이나 웹의 사용자 인증을 위해 사용하는
    암호화된 토큰을 의미한다.
    JWT 정보를 request에 담아
    사용자의 정보 열람, 수정 등 개인적인 작업들을 수행할 수 있다.

  2. XSS(Cross Site Scripting)
    XSS라고 불리는 이유는 CSS가 이미 약자가 있기 때문이고
    code injection attack이라고도 한다.

XSS도 다양한 공격 방법이 있는데 우선은
공격자가 의도하는 악의적인 js 코드를 피해자 웹 브라우저에서 실행시키는 것
정도로 알고 있으면 된다.

이 방법으로 피해자 브라우저에 저장된 중요 정보들을 탈취 가능하다.

  1. CSRF(Cross Site Request Forgery)
    정상적인 request를 가로채 피해자인 척 하고 백엔드 서버에
    변조된 request를 보내 악의적인 동작을
    수행하는 공격을 의미한다. (피해자 정보 수정, 정보 열람)

ex) 내가 쓰지 않은 광고성 글이 페이스 북에 올라갈 수 있음

  • (04-18) 내용 추가
    대략적인 공격 과정은 다음과 같다. (요청 url은 알고 있다고 가정)
  1. 공격자는 유저가 img를 열람하도록 하거나 link를 클릭하도록 유도한다.

  2. 이 action은 사용자 의도와는 관계없이 http request를 보낸다.

  3. 유저가 로그인이 되어있는 상태라면 이 request는 정상적으로 서버에 동작을 수행한다.

  4. XSS 공격을 막는 것은 웹 보안을 위한 최소한의 조치이다.
    아무리 다른 공격(CSRF 등)에 대한 방비를 열심히 해도
    XSS가 뚫린다면 아무 소용이 없다.

Js 코드로 의도하지 않은 request를 날린다던가
localStorage, 변수 값 등 모든 것이 탈취 가능하기 때문이다.

XSS 공격 방지는 웹 보안의 뿌리라고 할 수 있다.

이제 JWT를 저장하기 위한 장소에는 2가지 정도가 남아 있다.
localStorage와 cookie.

먼저 결론부터 얘기하면 둘 중에 정답은 없다.
각각 장단점이 있고 개발 환경이 다르기 때문에
(서드파티 api를 사용해서 백엔드와 소통이 불가능하다던가...)
무엇이 더 우월하다는 이야기는 할 수 없다.

그럼에도 best option은 존재하니
궁금하신 분들은 결론을 봐주시길 바란다.

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

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

  1. cookie에 저장
    👍 장점
    XSS 공격으로부터 localStorage에 비해 안전하다.

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

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

참고 : 'About XSS Attack' 부분 참고

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

(자동으로 request에 실리는 쿠키)

최근에는 쿠키의 CSRF 취약점을 막기 위해 쿠키의 same-site 속성과 js의 fetch api 속성의 기본값 등으로 request에 쿠키를 싣지 않음 이 설정되어있다.
쿠키가 request에 실리지 않는다면, 다음의 글을 보자

  1. best option
    가장 좋은 방법으로는
    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를 막을 수 있다.

참고
프론트에서 안전하게 로그인 처리하기 (ft. React)
'store your refresh token in the cookie' 부분 참고

  1. cookie와 localStorage, 굳이 1개를 택하라면?
    반드시 cookie와 localStorage, 둘 중 하나를 선택하라고 한다면
    나는 localStorage를 선호한다. 이유는 다음과 같다.

cookie의 httpOnly 옵션도 XSS 공격을 완벽히 막을 수 없다.
어차피 XSS 방어는 필수적이므로 cookie의 장점이
매력적이게 보이지 않는다.

cookie를 사용한다면 백엔드 api에 내가 사용하는 cookie를 위한
설정을 요구해야한다.
백엔드와 조율이 잘 되는 상태면 cookie를 사용해도 문제 없지만
서드파티 api의 경우 거의 불가능하므로 localStorage가 더 좋을 것 같다.

mdn은 저장소로 쿠키를 추천하지 않는다. 대신 ModernStorage(localStorage와 sessionStorage)를 추천한다.
참고 - mdn cookie

반대로, cookie를 지지하는 입장도 들어보자

🙋‍♂️ cookie를 지지하는 입장

CSRF 공격은 다루기 쉬운 반면 프론트엔드 크기가 크면 클수록
XSS 공격을 막기위한 작업은 많아지므로 쿠키 사용을 추천한다고 한다.
'Luc Engelen’s opinion' 부분 참고

  • 리뷰어님의 의견 (04-09 업데이트)

나의 생각

  1. CSRF, Cross-Site Request Forgery. 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을

  2. xss는 자바스크립트 코드를 삽입해 개발자가 고려하지 않은 기능이 작동하게 하는 방식

jwt방식으로 생성된 토큰을 쿠키나 로컬스토리지에 저장이 가능.
1. 로컬스토리지에 저장시 장점 :

  • js 코드에 의해 헤더에 담기므로 , CSRF 공격에는 안전,
    단점
  • XSS에 취약하다.
  • Js 코드 한 줄만 주입하면
    localStorage를 공격자가 내 집처럼 드나들 수 있다.
    cookie에 저장시 장점
  • XSS 공격으로부터 localStorage에 비해 안전하다. (서버에서 httpOnly 옵션을 지정해주면 js에서 쿠키에 접근이 안됨)
  • CSRF 공격에 취약하다.
    이 두개의 장단점으로 인해 best Option으로 refresh token을 사용하는 방법

refresh token을 httpOnly 쿠키로 설정하고 url이 새로고침 될 때마다 token을 request에 담아 새로은 accessToken을 발급 받는다.

  • 이걸 바탕으로 프로젝트에서 백에서 토큰을 생성해서 내가 로컬이나 세션스토리지에 저장하는 방법,
    hidden 방식으로 받은 정보를 보내는 방법 공부 숙지가 필요 할 거 같다..
    제발 복잡하지 않았으면 좋겠다.
profile
코린이

1개의 댓글

comment-user-thumbnail
2022년 7월 6일

위범석 화이팅 ♥︎

답글 달기