무지를 아는 것이 곧 앎의 시작

Web

리프레시 토큰 탈취 대응 전략을 고민하다 도달한 세션쿠키 vs 토큰에 대한 고민

Alex96 2022. 11. 9. 16:23

세션 쿠키 방식과 토큰 방식 간단정리

웹 어플리케이션을 구현하는 데에 대표적인 인증방식 중에 세션과 쿠키를 이용한 인증방식과 토큰 기반의 인증 방식이 있다. 각 방식마다 특징이 다르다.

세션 쿠키 방식

세션과 쿠키를 이용한 로그인 방식의 경우 서버에서 사용자의 로그인 정보를 세션으로 저장하고 있게 된다. 그리고 짧은 유효기간을 둔 세션ID를 클라이언트의 쿠키에 저장하여 해당 쿠키를 서버에서 까보고 세션 유효기간을 늘려주는 방식으로 동작한다.

토큰 방식

토큰방식의 경우 토큰 자체에 정보를 저장하기 때문에 서버에 따로 자원을 저장하지 않고 로그인을 구현할 수 있다. 서버는 토큰의 유효성을 검증하는 수단만 가지고 따로 토큰을 추적하지 않기 때문에 서버의 부담을 줄일 수 있다.

장단점 정리

세션 쿠키를 이용한 방식은 서버에서 세션 상태를 저장하기 때문에 통제에 용이하다.

ex. 강제 로그아웃, 계정별 접속 갯수 제한 …

하지만, 서버에 자원을 저장하기 때문에 서버의 부담이 증가한다.

토큰 방식의 경우 서버에 자원을 저장하지 않을 수 있기 때문에 서버의 부담을 줄일 수 있다.

하지만, 저장하지 않을 경우 서버에서 통제하기가 까다롭기 때문에 해당 부분에 대한 전략을 고민해야한다.

엑세스 토큰과 리프레시 토큰

토큰 방식을 구현할 때 엑세스 토큰만 발급하지 않고 짧은 엑세스 토큰 + 긴 리프레시 토큰 조합으로 사용할 수 있다.

리프레시 토큰이 왜 필요한데?

엑세스 토큰은 세션과 달리 만료 기간을 짧게 두면 사용자 입장에선 짧은 기간마다 새로 로그인 해야하는 불편함을 겪는다. 만료기간을 짧게 두는 이유는 엑세스 토큰 자체로 그 토큰이 가진 권한을 모두 사용할 수 있기 때문에 탈취 되더라도 자원이 공격자에게 노출되는 시간을 최소화하기 위함.

아무튼 위의 불편함을 해소하기 위해 리프레시 토큰을 같이 사용한다. 리프레시 토큰은 엑세스 토큰을 재발급 받는 용도로 쓰이는 토큰이다. 그래서 긴 만료시간을 가지고 엑세스 토큰을 재발급 해주면서 사용자에게 자주 로그인해야하는 불편함을 해소할 수 있다.

리프레시 토큰의 탈취를 대비하려면?

리프레시 토큰이 탈취될 경우 긴 기간동안 공격자가 해당 사용자의 엑세스 토큰을 마구잡이로 찍어낼 수 있는 매우 좋지 못한 상황이 된다. 어떻게 대비해야 할까?

뭐 여러 방법이 있겠지만, 일단 필수적으로 리프레시 토큰은 서버에 저장해야 한다.(전략을 어떻게 짜느냐에 따라 엑세스 토큰도 저장하기도 한다.) 이유는 리프레시 토큰이 탈취되었을 때 해당 토큰을 무효화하기 위함인데, 무효화하려면 서버에서 해당 리프레시 토큰을 추적해야 한다. 토큰 방식은 서버의 리소스를 사용하지 않을 수 있다는 장점이 희석되는 것이다.

토큰도 서버의 자원을 점유하고 세션 쿠키 방식도 서버 자원을 점유하는데…

서버가 다중화 되었다는 상황을 가정하고 생각해보겠다.

리프레시 토큰을 도입했을 경우 탈취에 대한 대비책을 세워 두는 것이 안전하고 이를 위해선 서버에서 토큰을 추적해야한다.

세션 쿠키 방식과 마찬가지로 서버에 자원을 점유하게 된다. 서버가 다중화 환경이라면 한 서버 인스턴스 내부의 저장소에 저장하면 각 인스턴스간 세션이든 토큰이든 공유되지 않으니 별도의 공유 저장소에 저장할 것이다.(예를 들면 레디스라든지… DB가 될 수도 있고)

그럼 둘 다 별도의 저장소에 로그인 정보를 추적하는 무언가를 저장해야 한다. 대체 차이점이 뭐가 있을까?

저장소에 접근하는 빈도를 고려해보자

세션 쿠키든 토큰이든 저장소를 사용해야 한다. 근데 세션 쿠키는 언제 저장소를 찔러야 하고 토큰은 언제 저장소를 찔러야 할까?

사용자 요청이 들어왔을 때 접근 순서를 정리해보자.

세션 쿠키

  1. 클라이언트에서 서버로 세션ID를 쿠키에 담아서 전송
  2. 서버에서 저장소에 세션ID가 있는 지 확인
  3. 확인되면 로직 실행 및 세션 유효기간 재설정

토큰 방식

  1. 클라이언트에서 서버로 Authorization헤더에 엑세스 토큰을 담아서 전송
  2. 서버에서 엑세스 토큰의 유저인걸 확인하고 로직 실행
  3. 엑세스 토큰이 만료되면 클라이언트에선 리프레시 토큰을 서버로 전송하면서 새 엑세스 토큰 요청
  4. 저장소에서 리프레시 토큰이 유효한지 확인
  5. 확인되면 새 엑세스 토큰 발급

저장소에 접근하는 빈도에 큰 차이가 있다. 세션 방식은 요청이 들어올 때마다 유효한 세션ID인지 검사하기 위해 매번 저장소를 찔러야 한다. 하지만 토큰 방식은 엑세스 토큰을 사용하는 대부분의 요청엔 저장소를 찌를 필요가 없다. 리프레시 토큰으로 새 엑세스 토큰을 발급할 경우에만 해당 리프레시 토큰이 유효한지, 비 정상적으로 많이 엑세스 토큰을 찍어내고 있는지 등등 판단하기 위해 그때 저장소를 찌른다.

즉 토큰이 저장소를 찌르는 빈도가 훨씬 낮기 때문에 비용이 적게 든다.

그럼 절대적으로 토큰이 좋아?

당연히 No다. 넷플릭스는 왜 세션 쿠키 방식을 채택할까? 넷플릭스 같은 경우는 한 계정당 동시 로그인 갯수를 4개로 제한하고 있다. 즉, 매 요청마다 그 계정의 유지되는 세션 갯수를 확인해줘야 한다. 이 경우엔 토큰을 파싱하는 비용을 줄이는 세션 쿠키 방식이 나을 수 있다. 각각의 특징을 이해하고 있으면 상황에 맞게 선택해서 사용할 수 있을 것 같다.

'Web' 카테고리의 다른 글

캐시와 관련된 HTTP 헤더들  (0) 2022.12.10
OAuth, OpenID  (0) 2022.11.08
내편 리프레시 토큰 도입기  (1) 2022.10.13