관리 메뉴

꿈꾸는 개발자

JWT 토큰 저장 방식?/위치? 정리 (보안) 본문

CS지식

JWT 토큰 저장 방식?/위치? 정리 (보안)

rickysin 2023. 5. 9. 16:18

배경 지식(토큰 인증 방식)

토큰 인증 방식은 사용자의 인증 정보를 서버 측이 아닌 클라이언트 측에 저장하는 방식이다. (세션 인증 방식이 가지고 있던 한계를 극복할 수 있음- 서버에서 관리하던 인증 정보에 대한 부담 완화). 

 

기본 흐름

JWT(Json Web Token)

토큰 기반 인증을 사용했을 때 대표적으로 사용하는 방식 중 하나가 JWT이다. JWT는 JSON 객체에 정보를 담아 이를 토큰으로 암호화하여 전송할 수 있는 기술을 의미한다. 클라이언트에선 서버에 요청을 보낼 때 JWT 토큰을 제공하면 서버에서 해당 토큰을 검증 후 유저 정보를 확인할 수 있다.

 

기본 구조(base64로 인코딩 된다)

  • header: 토큰 자체를 설명하는 데이터를 담고 있다.(암호화하는 방식): base64방식으로 인코딩한다. 얼마든지 디코딩될 수 있기 때문에 민간한 정보는 담지 않아야 한다.
  • payload: HTTP payload처럼 전달하고자 하는 내용을 담고 있다. 어떤 정보에 접근이 가능한지에 대한 권한, 유저 개인정보,  토큰 발급 시간 등 JSON형태 => base64로 인코딩되면 위 payload 완성
  • signature: 토큰의 무결성을 확인할 수 있는 부분, header+payload가 완성됐다면, signature는 서버의 비밀 키를 통해 해싱을 할 수 있다 

위험성 및 한계

 JWT를 탈취하기 위해서 사용할 수 있는 방법은 "XSS 공격"과 "CSRF 공격"이 있다. 만약 토큰이 탈취된다면, 개인 정보를 조회하거나, 접근성이 허용되지 않은 정보에 접근할 수 있게 됨으로 보안의 중요도는 매우 높다. 

 

토큰 방식의 한계

토큰 인증 방식에도 분명한 한계가 존재한다.

signature를 통해 위조 토큰을 분별할 수 있지만, 토큰 자체가 탈취됐을 경우 토큰 인증 방식의 한계가 분명해진다. 

 

  • 무상태성: 인증 상태를 관리하는 게 서버가 아니기 때문에 토큰을 강제로 만료시킬 수 없다. 따라서 만료될 때까지 사용자인 척 계속 요청을 보낼 수 있음
  • 유효기간: 토큰 만료 기간을 길게 설정하면 탈취 될 위험성이 증가하고, 짧게 설정하면 사용자 경험에 안 좋은 영향을 미친다

한계 보완

토큰 인증 방식의 한계를 극복하기 위해 고안된 방법 중 하나로 accessTokenrefreshToken 방식이 있다. 

  • accessToken: 서버에 접근하기 위해 axios 등 authorization header에 넣어주는 토큰이다. 위에서 언급한 토큰과 비슷한 역할을 담당한다. (보통 만료 기간을 24시간으로 설정한다)
  • refreshToken: 서버에 접근을 위해 존재하는 토큰이 아닌, 엑세스 토큰이 만료됐을 경우 accessToken을 재발급 받기 위해 사용되는 토큰이라고 생각하면 된다. 따라서, RefreshToken(만료기간) > AccessToken(만료기간)으로 보통 설정된다.

물론 refresh 토큰 마저 탈취된다면 큰 문제가 발생하겠지만, 이러한 상황을 방지하기 위해서 refresh 토큰은 보통 서버에 관리를 한다.


저장 위치

그렇다면 클라이언트 측에서 사용자가 로그인 후 서버로부터 토큰을 받게 됐을 때 이것을 어디에 저장하고 사용하는 것이 바람직한 방법일까? 토큰을 저장할 수 있는 방식 중 대표적으로 비공개 변수, 로컬 스토리지, 세션 스토리지, 쿠키로 분류를 할 수 있다. (그냥 일반적인 토큰 방식이든 accessToken,RefreshToken 방식이든) 토큰 방식 자체가 클라이언트에서 토큰을 저장해야 하기 때문에 위의 고민은 필수적이다. 

 

  • 비공개 변수의 경우 브라우저가 새로고침될 때마다 유지가 되지 않기 때문에 사용자는 새로고침 할 때마다 재접속을 해야하는 불편함을 감수해야 한다. 따라서, 그렇게 적극적으로 사용되는 방법은 아닌듯 하다. (하지만 refreshToken을 통해 재접속하는 API를 작성하면 되다는 글을 보긴 했는데 정확도 의심되기 때문에 참고 사항 정도로 일단 보류하고자 한다)

로컬 스토리지+ 세션 스토리지(공통)

  • 쿠키 방식과 다른 점: 
    • 쿠키와 다르게 네트워크 요청 시 서버로 전송되지 않는다. 쿠키보다 더 많은 자료를 보관할 수 있다
    • 서버가 HTTP 헤더를 통해 스토리지 객체를 조작할 수 없음 웹 스토리지 객체 조작은 모두 JS로(이것은 추후 보안에 문제가 된다)
    • 웹 스토리지 객체는 도메인/프로토콜/포트로 정의되는 origin에 묶여있다. 다른 도메인에서 접근 시 CORS 에러가 발생하게 됨
  • 로컬 스토리지: 많이들 사용하는 방식인 것 같다. 나도 이 방법을 위주로만 사용했었던 것 같은데. 일단 브라우저가 새로고침되더라도 정보들이 유지되기 때문에 사용자 편의성이 높은 편이다(브라우저를 닫고 다시 열어도 정보들이 유지된다). 하지만, JS 코드를 통해 접근이 가능하기 때문에 XSS 공격에는 취약하고 CSRF 공격에는 안전한다. 
  • 세션 스토리지: 로컬 스토리지에 비해 제한적이다. 현재 떠 있는 텝에서만 유지되는 특징을 가진다. 새로 고침할 때는 사라지지 않지만, 탭을 닫고 다시 열 때는 데이터가 사라진다. 

쿠키

MDN 공식 문서에 따르면 쿠키에 저장하는 방식보단 로컬 스토리지에 저장하는 형식을 조금 더 권장하는 듯하다.

  • 그 이유는 모든 요청에 쿠키가 함께 전송되기 때문에 성능 저하의 원인될 수 있다고 합니다. 

보안적인 측면에서 쿠키 또한 JS로 접근이 가능하기 때문에 서버측에서 HTTP Only,secure,Samesite 등 옵션을 걸어줘여 합니다. 위와 같은 방법으로 쿠키 탈취/JS 접근도 제한할 수 있습니다. 


결론 

본 글은 팀 프로젝트를 진행하면서 제기된 토큰 저장 방식에 대한 고찰을 정리하고자 작성됐다. 아직 어떠한 형식으로 토큰을 저장할지 완벽하게 결정하지 않았지만, 공식문서 등 여러 상황들을 종합적으로 고려해 결정하고자 한다. 결론 내용은 프로젝트를 진행하면서 추가적으로 보충하고자 한다 


참고 자료

https://jwt.io/introduction/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

https://oauth.net/2/refresh-tokens/

 

What is a Refresh Token - OAuth 2.0

 

oauth.net

https://velog.io/@compy/JWT%EB%A5%BC-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0-%EC%BF%A0%ED%82%A4%EC%99%80-%EC%9B%B9-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80

 

JWT를 조금 더 안전하게 저장하기 & 쿠키와 웹 스토리지

사용자의 인증/인가 작업에 활용되는 JSON Web Token을 안전하게 저장할 방법이 무엇일까? 직접 한번 프론트엔드와 백엔드 범위에서 조사해보았다!

velog.io

https://ko.javascript.info/localstorage

 

localStorage와 sessionStorage

 

ko.javascript.info

https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies#%EC%BF%A0%ED%82%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0

 

HTTP 쿠키 - HTTP | MDN

HTTP 쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각입니다. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이

developer.mozilla.org


추가적으로 참고하면 좋을 것 같은 글 (비공개 변수에 Token을 저장하는 방식에 대해 다루고 있음)

https://velog.io/@ohzzi/Access-Token%EA%B3%BC-Refresh-Token%EC%9D%84-%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

 

Access Token과 Refresh Token을 어디에 저장해야 할까?

F12 팀 프로젝트는 JWT 토큰을 Access Token으로 하는 인증 인가 서비스를 구현하고 있습니다. 로그인을 하면 백엔드 서버에서 토큰을 만들어 보내주고, 이후 클라이언트에서 보내는 요청의 Authorizatio

velog.io