서버 기반 인증 vs 토큰 기반 인증

Updated:

서버(Session/Cookie)기반 인증 방식과 JWT 토큰 기반 인증 방식의 차이

서버 기반 인증

이전에 사용되던 HTTP 프로토콜 인증 방식에서는 요청에 따른 응답을 받으면 연결이 끊어지고 통신이 종료되면 어떠한 상태 정보도 남지 않는데, 그로 인해 로그인 후 다시 웹페이지에 접근하면 로그인 상태가 유지되지 않는다는 문제점이 있다.

이러한 HTTP 프로토콜의 인증 문제를 해결하기 위해 사용하는 방법으로 세션과 쿠키를 사용하였다.

세션과 쿠키를 사용한 인증 방식은 다음과 같다.

  1. 사용자가 로그인 한다.

  2. 서버는 요청이 들어오면 사용자를 검증하고 유효할 경우 사용자의 고유한 ID값을 부여하여 세션 저장소에 저장한 후, 이와 연결되는 세션 ID를 생성하여 response header에 포함시켜 반환한다.

  3. 사용자는 서버에서 해당 세션ID를 받아 쿠키에 저장을 한 후, 제한된 end point(인증이 필요한 요청)에 접근할 때 마다 쿠키를 request header에 포함시켜 보낸다.

  4. 서버에서는 쿠키를 받아 세션 저장소에서 검증한 후 요청에 해당하는 데이터를 반환한다.

이러한 세션/쿠키 방식은 어떤 특징이 있을까?

먼저, 쿠키가 요청 중 노출되어도 쿠키 자체에는 중요한 정보가 담겨있지 않다. 그러나 만약 누군가 쿠키 자체를 훔쳐 세션에 접근한 뒤 중요한 정보를 빼갈 수 있는데, 이를 방어하기 위해 세션에 유효시간을 넣거나 HTTPS를 사용해 요청을 훔쳐도 그 안의 정보를 보기 힘들게 한다.

또한, 쿠키를 통해 세션에 접근하면 세션 ID로 사용자를 구분할 수 있으므로 일일이 사용자 정보를 확인할 필요가 없다.

하지만 단점 또한 존재한다. 서버(메모리 or DB)에 세션을 저장하기 때문에 사용자 수가 많아지면 서버의 부담이 늘어난다. 그리고 서버 확장성(scalability)이 나빠진다. 서버 사양 업그레이드뿐만 아니라 늘어나는 트래픽을 감당하기 위해 여러 프로세스를 돌리거나, 여러 대의 서버 컴퓨터를 추가하는 것이 어려워진다.

뿐만 아니라, 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 여러 도메인에서 관리하기 번거롭다.

그렇다면 토큰 기반 인증 방식은 어떨까?

토큰 기반 인증

토큰 기반 인증은 stateful 서버와 반대적 개념인 stateless 서버를 사용하며 상태 정보를 유지하지 않는다. 또한, 서버가 전달받은 토큰을 검증만 하면 되기 때문에 서버의 부담을 줄이고 서비스의 확장성을 높일 수 있다.

토큰을 사용한 인증 방식은 아래와 같다.

  1. 사용자가 로그인 한다. (로그인 정보를 서버로 request)

  2. 서버는 요청이 들어오면 사용자를 검증하고 유효할 경우 정상적으로 발급된 토큰임을 증명하는 signature를 갖는 토큰을 클라이언트에 반환한다.

  3. 클라이언트는 토큰을 저장하고 서버 요청 시 해당 토큰을 Request header에 담아 서버에 전달한다.

  4. 서버는 토큰을 검증한 후, 요청에 응답한다.

이러한 토큰 기반 인증 방식은 다음과 같은 특징을 갖는다.

먼저, 서버에 세션을 유지하고 저장해야하는 서버 기반 인증 방식과 다르게, 토큰 기반 방식은 서버의 상태를 유지할 필요가 없기 때문에 서버에 부하가 적고 확장성 또한 높다.

또한, 플랫폼 간 권한을 공유할 수 있는데 OAuth 와 같이 페이스북, 구글, 트위터 등 SNS 계정을 이용하여 웹서비스에 로그인하는 것이 가능해진다. 이와 비슷한 맥락으로 모바일 앱 사용에서도 세션 기반 인증보다는 훨씬 편리하다. 쿠키를 사용할 필요 없이 헤더에 토큰만 넣어주면 되니 말이다.

하지만, 토큰 방식 또한 단점이 존재한다.

토큰은 강제로 만료시킬 수 없다. 따라서, 만약 토큰이 해킹당했다면 해커는 토큰이 만료될 때까지 계~~속해서 서버에 요청을 보낼 수 있는 것이다. 그렇다고 이를 보완하기 위해 토큰 만료 주기를 짧게하면 사용자가 수시로 로그인해야하는 불편함이 생긴다.

따라서, 이러한 보안 문제를 위해 보통은 Access Token과 Refresh Token을 함께 사용한다.

사용자가 처음 로그인을 할 때 AccessToken과 RefreshToken을 함께 발급하도록 한다. 보통 Access Token은 20~30분, Refresh Token은 한달 정도의 만료 기간을 부여한다.

클라이언트는 AccessToken이 만료되었다는 오류를 받으면 따로 저장해두었던 RefreshToken을 이용하여 AccessToken의 재발급을 요청한다. 서버는 유효한 RefreshToken으로 요청이 들어오면 새로운 AccessToken을 발급하고, 만료된 RefreshToken으로 요청이 들어오면 오류를 반환해, 사용자에게 로그인을 요구하게 된다.

여기서, AccessToken은 서버에 따로 저장해 둘 필요가 없지만, RefreshToken의 경우 서버의 stroage에 따로 저장해야한다. Access Token 재발급 요청을 위한 것이다. 이때, RefreshToken은 탈취되어서는 곤란하므로 클라이언트는 보안이 유지되는 공간에 이를 저장해두어야 한다. 물론 Refresh Token은 서버에서 따로 저장하기 대문에 강제로 토큰을 만료시키는 것이 가능하다.

요즘 토큰 방식으로 JWT Token이 주로 사용되고 있다. JWT Token의 상세 내용과 Spring Boot에 적용하는 방식은 다음 포스팅에서 알아보자.