이번에 진행하는 프로젝트에서 유저 인증 방식으로 JWT 인증 방식을 채택하여 사용하였다. 문득 생각이 든게, 'Local storage에 토큰을 저장하는 것이 안전한가 ?' 였다.
이러한 고민에서 정리해보게 된 글이다.
JWT는 JSON Web Token의 약자이고, 암호화 된 JSON 객체이다. 한번 서명 된 토큰은 어떤 식으로든 변조되지 않으며, 토큰 생성시 사용했던 서명(Signature)와 검증하려는 토큰의 서명이 다르면 유효하지 않은 토큰으로 생각하여야 한다.
JWT는 base64 기반의 문자열로 이루어진 세 부분으로 나뉜다.
대부분의 사람들은 JWT를 웹 브라우저의 Local storage에 저장하는 경향이 있다. (나 또한 그러하다)
이러한 경우에는 XSS 라는 공격에 취약해진다고 한다.
악의적 의도를 가진 사람이 동일한 도메인에서 실행 되는 모든 Javascript 코드를 통해 Local storage에 접근 할 수 있다는 사실을 악용하는 것이다.
XSS에 대한 자세한 내용은 이곳을 참조해보도록 하자 !
다른 웹 스토리지 중 하나인 Session Storage도 마찬가지다. 이 또한 Javascript 코드로 접근이 가능하다. 또 다른 단점으로는 브라우저를 종료하게 되면 스토리지 내의 모든 것들이 삭제 된다. 사용자들 입장에서는 로그인을 또 해야한다는 번거로움이 있을 수 있다.
어찌보면 브라우저 종료 시 내용이 모두 삭제 되어 local storage 보다는 안전한거 같기도 하지만, XSS 공격에 취약한건 마찬가지이다.
쿠키는 상태를 저장하지 않는 HTTP의 특징인 보완하기 위해 생기게 되었고, 인증 방식으로도 오랜 시간 사용 되고 있다.
서버로의 요청시 자동으로 요청 헤더에 포함 되어 전송 되어 간편하기도 하며, HttpOnly 플래그를 설정하면 웹 스토리지의 단점이었던 Javascript로의 접근도 불가하게 된다.
한 단계 더 나아가서 Secure 옵션을 주게 되면 HTTPS 통신으로만 전송 될 수 있어 좀 더 나은 보안책이 될 수 있을 것이다. (오늘 날의 HTTPS는 필수적이라고 할 수 있겠다.)
이 정도만 봐도, 웹 스토리지의 사용보다 쿠키를 사용하는 것이 보안적 측면에서는 훨씬 더 좋아보인다.
하지만 쿠키 또한 취약점이 존재한다. 바로 CSRF(Cross Site Request Forgery) 공격이다. 이는 쿠키 전송 방식의 취약점을 이용한다. 특정 사이트가 사용자의 브라우저를 신뢰한다는 점을 이용하게 되는데, 쿠키가 전송 될 때 목적지의 도메인에 따라서 포함 여부가 결정 되지 출발지가 어디인지에 대해서는 신경쓰지 않는다는 점이다.
csrf.com에 이런 코드가 심어져있다고 가정해보자.
<img src="http://example.com/api/user?id=hack&password=123">
위와 코드를 심어 두었다고 한다면, 이를 몰랐던 사용자는 접속 하자마자 해커가 심어둔 example 사이트의 api를 해커의 의도대로 호출하게 된다. A의 브라우저에는 example 사이트에서 얻어둔 유효한 쿠키가 있기 때문에 해당 api는 요청 작업을 처리하게 된다.
그동안 개발을 공부 해보며, 어떤 식으로 유저 인증을 구현할까? 정도였지, 보안적인 부분에 대해서는 고민해 본적이 없었던거 같다. 높은 수준의 보안이 요구되는 사이트를 구현해 본 것은 아니지만 그동안 이러한 부분을 고민해보지 못한 것에 대해서는 아쉬움이 있다.
완벽한 보안은 없다.
항상 보안에 취약점이 생길 것을 고려하여야 할 것이고, 이를 의식하고 개발하여야 할 것이다.