주요 내용으로 건너뛰기

공부: session-cookie vs jwt auth

두 인증 방식의 차이와 클라이언트와의 결합

지금까지 node js - react js 를 배워오면서 가장 이해가 어려웠던 부분은 결국 인증 파트였다.

대표적인 인증 모듈인 passport js 를 접한 것을 계기로 여러가지 에러들을 겪으면서 조금씩 이해해왔는데

처음부터 궁금했고 얼마전까지도 제대로 이해하지 못했던 메커니즘이 있었다.

그 중 하나가 세션-쿠키 기반 인증 방식이 어떻게 클라이언트와 결합할 수 있는가였는데,

그 이유는 대부분의 유튜브 비디오나 블로그의 설명이 node js 앱을 기준으로 설명했기 때문이다.

Node js 앱의 경우 인증 미들웨어를 통해 passport js 에서 넘겨주는 req.user를 받아서 인증여부를 따질 수 있지만 브라우저 환경에서는 그 방법을 사용할 수가 없다. 

왜냐하면 만약 브라우저 쿠키에 민감한 정보(세션 키나 유저의 개인정보 등)를 넘겨준다면 보안 취약점이 발생하기 때문이다. 

그래서 쿠키는 httpOnly flag와 max-age flag를 통해 자바스크립트로 컨트롤할 수 없고 동시에 일정 시간이 지나면 만료되게 설정해야된다.

다만 내가 문제라고 생각했던 부분은 httpOnly flag를 세웠을 때 document.cookie를 통해 쿠키를 조작할 수 없게 된다면 어떻게 헤더에 쿠키를 포함해서 요청을 보낼 수 있는가하는 것이었는데,

답은 가까이에 있었다.

답은 credentials 옵션('same-origin')을 설정하면 같은 도메인에 해당되는 쿠키 전부를 담아서 전송해준다는 것이었다.

굉장히 허무했지만 결국 모든 원인은 기본이 되는 쿠키와 같은 개념을 제대로 이해하지 못한데 있을 것이다.

적어도 mdn 문서를 한 번이라도 정독했으면 이런 일은 안 일어났을텐데 ㅜ

세션-쿠키 인증을 이해하는 핵심은 결국 http라는 stateless한 녀석과 server-client가 어떻게 정보를 공유할 수 있게 만드는가 인것같다. 서버에서는 민감한 정보에 대한 키인 세션키를 생성, 쿠키의 형태에 클라이언트에 발급하고, 클라이언트에서는 http요청을 할 때마다 자신이 인증 사용자임을 밝히기 위해 상태정보를 담은 쿠키를 헤더에 담아 보내는 것이다. 

마지막으로 세션-쿠키 인증에서 유의해야 하는 것은 xss/csrf 공격인데

xss 공격의 경우 httpOnly쿠키를 통해 방지할 수 있고, csrf 공격의 경우 node js의 csurf 모듈을 통해 관리할 수 있다.

get요청이 아닌 post delete put 등 데이터에 대한 수정이 가해지는 요청의 경우 적절한 csrf 토큰을 요구한다면 이를 예방할 수 있다.


다음은 jwt 인증 방식이다. jwt는 json web token의 줄임말로 서버에서 세션을 저장하는 대신 

브라우저에(localStorage / sessionStorags / cookie) 토큰(토큰/리프레쉬 토큰)을 저장하게끔하고

http 요청을 보낼 때마다 그 토큰을 헤더에 담아 서버에 특정 api 호출을 하는 방식이다.

세션-쿠키 인증 방식에 비해 scale out 하기가 쉽고 서버에 부담이 덜한 것이 특징이다.

또한 자바스크립트로 컨트롤 할 수 없는 httpOnly 쿠키와는 달리 localStorage api 는 자바스크립트로 컨트롤이 가능하다.

거기에 인증 방법 또한 node js 의 jsonwebtoken 모듈을 이용하면 굉장히 간편하다. 

다만 토큰을 서버측에서 폐기할 수 있는 방법이 전혀 없고, 그로 인해 토큰을 탈취당했을 때 굉장히 보안 취약점을 드러낸다.

그럼에도 토큰의 age를 짧게 설정한다면 크게 걱정할 사안은 아니라고 생각한다.


두 가지 방식 모두를 사용해본 결과 내가 만드는 앱들은 대부분 학습용으로 만든 것들이었기 때문에 편의성 측면에서는 어느 쪽이 확실하게 낫다는 생각은 들지 않았다.

그럼에도 두 가지 방식 모두 구현이 크게 어렵지 않았지만 조금 더 편리한 쪽을 고르라면 역시 jwt 토큰 방식이 아닐까 싶다.


이준형 님의 창작활동을 응원하고 싶으세요?

댓글

SNS 계정으로 간편하게 로그인하고 댓글을 남겨주세요.