4장. JWT 이해 및 적용

사용자의 인증정보를 관리하기 위해서, 우리는 토큰 기반 인증 시스템을 사용 할 것 입니다. 사용자의 인증정보를 관리하는 방식은 크게 두가지로 나뉘는데요, 첫째는 세션 기반 인증입니다. 이는 서버 기반 인증이라고 불리기도 합니다. 이 인증 시스템은 이전부터 수 많은 웹서비스로서부터 사용이 되고 있는데요, 이름이 그렇듯, 만약에 유저가 로그인을 하게 되면, 서버측에서 유저가 현재 로그인 중이라는 인증정보를 기억하고 있어야 합니다. 그리고 이 정보를 세션 이라고 부릅니다.

세션을 유지하기 위해서는 여러가지 방법이 사용되는데, 메모리, 디스크, 데이터베이스 시스템에 이를 담곤 합니다. 하지만 이 시스템엔 몇가지 문제점이 있는데, 이 문제점들은 큰 규모의 어플리케이션을 개발하는 것에 있어서 걸림돌이 되곤 했습니다.

서버 기반 인증의 문제점

서버기반 인증의 문제점은 크게 2가지로 있습니다.

첫째는, 세션을 유지하게 될 때, 로그인중인 유저의 수가 많아진다면 성능에 무리가 가게 됩니다. 이 정보를 메모리에 넣게 된다면 램이 과부화가 되고, 데이터베이스에 넣게 된다면 데이터베이스의 성능에 무리가 가게 됩니다.

두번째는, 서버 확장이 어려워진다는 점입니다. 여기서 서버 확장은, 단순히 서버의 사양을 업그레이드 하는 것 말고, 더 많은 트래픽을 감당하기 위하여 여러 프로세스를 돌리거나, 여러 서버 컴퓨터를 추가하여 로드밸런싱을 할때를 의미합니다. 세션을 사용하면서 분산된 시스템을 설계하는건, 세션의 정보가 분산된 프로세스간에 동기화가 되야하므로, 과정이 매우 복잡합니다.

토큰 기반 시스템이 제공해주는것은?

토큰 기반 시스템은 stateless 합니다. 이 용어의 의미는 '무상태' 라는 뜻 인데요. 서버시스템측에서 더 이상 유저의 정보를 유지하지 않고, 유저가 회원 인증을 하게 될 때 토큰 을 발급해줌으로서 유저가 자기 자신임을 인증 할 수 있게 해줍니다. 발급이 된 토큰은, 토큰의 유효기간, 그리고 정보를 담고 있으며, 해싱 알고리즘을 통해 인증이 되어있어서 서버에서 검증을 통하여 처음 서버가 발급해주었던 정보가 변조되지 않았음을 보장 해 줄 수 있습니다.

토큰을 사용함으로서, 서버를 확장하게 될 때에 매우 용이해지게 됩니다. 서버 시스템이 분산이 되어있어도, 유저는 같은 토큰으로 서버에 요청을 하면 되고, 서버는 그저 그 토큰이 위조되지 않았는지만 검증을 하고 데이터베이스 조회도 할 필요 없이 바로 유저임을 신뢰하고 처리를 하면 되기 때문이죠.

추가적으로, 토큰을 사용하면 플랫폼간 권한을 공유 할 수 있습니다. 예를들어서, 우리가 다음 강의에서 페이스북 / 구글 계정을 통한 소셜 로그인을 구현하게 될 텐데, 이게 가능한 이유도 구글과 페이스북에서 토큰기반인증 시스템을 사용하기 때문입니다. 소셜 로그인 과정에서, 구글/페이스북 플랫폼에서 로그인을 하고, 해당 플랫폼이 토큰을 발급을 해주면 우리의 백엔드 서버에서 이를 통하여 회원정보를 가져오고 우리의 서비스에 계정 생성을 하게 됩니다.

마지막으로, 토큰 기반 시스템은 모바일 어플리케이션에서 사용하기에 편해집니다. 만약에 세션 기반 인증을 사용한다면, 쿠키를 사용해야 하기 때문에, 쿠키 매니저를 따로 관리해줘야 하지만, 토큰을 사용한다면 웹 요청 API 에 헤더에 넣어서 사용해주면 되기때문에 더이상 쿠키 매니저를 사용 할 필요가 없어지죠.

JWT 에 대한 더 많은 정보

더 많은 정보는 블로그 포스트 를 참조해주세요.

토큰 저장 위치

서버가 토큰을 발급해주면, 브라우저에서 사용자 / 서버간에 토큰이 전달되는 방식은 크게 두가지로 나뉩니다. 첫번째는, 로그인에 성공하게 되었을 때 서버가 토큰을 응답정보에 토큰을 넣어서 전달하도록 하고, 해당 값을 웹 스토리지 (localStorage 혹은 sessionStorage) 에 넣고, 그 다음부터 웹 요청을 할 때마다 HTTP 헤더 값에 넣어서 요청하는 방법이 있습니다.

이 방법은, 구현하기 쉽고, 하나의 도메인에 제한되어있지 않다는 장점이 있지만, XSS 해킹 공격을 통하여 해커의 악성스크립트에 노출이 되는 경우 매우 쉽게 토큰이 탈취 될 수 있습니다. 그냥 localStorage 에 접근하면 바로 토큰에 접근 할 수 있기 때문이죠.

이에 대한 대안, 두번째 방식은 이 토큰을 쿠키에 넣는 것 입니다. 쿠키를 쓰지 않으려고 토큰을 쓰는 줄 알았는데, 갑자기 이렇게 설명을 하니 헷갈릴 수도 있습니다. 쿠키를 사용한다고해서 세션을 관리하는것은 아니고, 그저 쿠키를 정보 전송수단으로 사용 할 뿐입니다. 이 과정에서, 서버측에서 응답을 하면서 쿠키를 설정 해 줄 때 httpOnly 값을 활성화를 해주면, 네트워크 통신 상에서만 해당 쿠키가 붙게 됩니다. 따라서, 브라우저상에서는, 자바스크립트로 토큰값에 접근하는것이 불가능해지죠.

만약에 모바일 어플리케이션도 개발을 하게 된다면, 서버측에서 JWT 를 헤더 값으로도 받을 수 있게 하여 쿠키 혹은 헤더 둘 중 존재하는것을 토큰으로 인식하여 사용하도록 구현을 하면 됩니다.

두번째 대안에 대한 단점은, 쿠키가 한정된 도메인에서만 사용이 된다는 점 입니다. 이 부분은, 토큰이 필요해질 때 현재 쿠키에 있는 토큰을 사용하여 새 토큰을 문자열로 받아올 수 있게 하는 API를 구현하여 해결하면 됩니다.

또 다른 단점은, XSS의 위험에서 완벽히 해방되는 대신, CSRF 공격의 위험성이 생긴다는 점 입니다. CSRF은, 계정정보를 탈취하는것은 아니지만, 스크립트를 통하여 사이트의 외부에서 사이트의 API 를 사용하는것 처럼 모방하는 것 입니다. 혹은, 사이트 내부에서 스크립트가 실행되어 원하지 않는 작업이 수행되게 할 수도 있습니다.

CSRF 공격의 예제는 다음과 같은 항목들이 있습니다.

스크립트에 노출되는 순간...

  • 유저도 모르는사이 탈퇴해버리기
  • 덧글을 자동으로 작성
  • 포스트를 자동으로 작성
  • 회원정보 변경

하지만, 너무 걱정하지는 마세요, CSRF의 경우엔 HTTP 요청 레퍼러 체크, 그리고 CSRF 토큰의 사용을 통하여 방지 할 수 있습니다.

정리를 하자면, 웹스토리지에 토큰을 담으면 XSS 에 취약하고, 쿠키에 담으면 CSRF 에 취약해집니다. 하지만, CSRF는 보안에 신경을 쓰면 차단 할 수 있습니다.

우리는 앞으로 인증시스템을 구현 하면서, 토큰을 httpOnly 속성이 활성화된 쿠키에 담아서 구현을 하도록 하겠습니다.

results matching ""

    No results matching ""