본문 바로가기

WEB

[WEB] 세션, 쿠키, 토큰에 대한 이해

0. 시작하며

프론트엔드쪽 일이든 백엔드쪽 일이든 종사하거나 웹개발/웹서버를 개발해본 사람이라면 세션 쿠키나 토큰을 한번쯤 들어봤을 것이다.

(사실 들어본게 아니라 알고 있어야 함)

필자는 JWT 토큰을 자주 사용하는데, 이번에 처음으로 쿠키를 써보면서 몰랐던 정보를 많이 알게되며 얻은 내용을 공유하고자 한다.

본 내용에서는 "쿠키"만을 사용하여 인증하는 방식은 서술하지 않는다.

 

1. 쿠키? 토큰? 그게 뭔데 X덕아

대부분의 서비스들은 유저 정보를 필요로 한다. (이유는 다양하다. 유저 별로 제공되어야할 정보가 구분되어야 하거나 등)

그리고 서비스들은 크게 2개의 레이어로 구분된다 → 클라이언트, 서버

클라이언트는 실제 사용자와 마주보는 화면으로 일반적인 웹 페이지가 해당된다.

반면, 서버 측은 사용자와 직접적인 상호작용을 하지 않고 웹 페이지를 통한 데이터 통신 (주로 HTTP)으로 대화를 한다.

이러한 서비스들은 유저 정보로 사용자를 식별할 수 있어야 하기에 로그인 정보를 저장하고, 저장된 정보를 바탕으로 유저들을 구분하고 검증할 수 있어야 한다. (이후 사진들에서 클라이언트는 제외하겠음)

 

하지만 만약 그러한 정보를 서버에서 저장하고 있다고 해도 아래와 같이 새로운 HTTP 요청을 보내면 서버에서는 보낸 요청이 어떤 유저가 요청한 것인지 모른다.

 

이렇게 되면 HTTP 요청을 보낼 때 마다 매번 로그인 인증을 하지 않는 한 유저를 식별할 수 없다.

이러한 상황을 해결하기 위해, 2가지 방식이 고안되었다.

바로 세션/쿠키 방식 토큰 방식이다.

 

1-1. 세션 & 쿠키 인증 방식

세션/쿠키 방식은 유저가 로그인했을 때 유저 정보와 생성된 Session ID를 함께 데이터베이스나 메모리에 저장하고, 클라이언트에는 Session ID가 담긴 쿠키를 반환하여 이후 요청에 쿠키가 오면 쿠키에 적힌 Session ID로 유저 정보를 찾아 검증/식별하는 방식이다. 보통 쿠키는 프론트엔드에서 직접 보내는 것이 아니라 서버에서 HTTP 요청의 응답 헤더에 Set-Cookie를 달아 반환하여 브라우저가 알아서 이후 요청들에 cookie를 같이 보내준다.

세션/쿠키 인증 방식

 

엥? 그럼 이론적으로 세션 ID만 알면 다른 사람 계정으로 인증 가능한거 아님?

그렇다. 이를 세션 하이재킹이라 하는데, 이러한 문제 뿐 아니라 XSS, CSRF 등의 공격 등에 취약하다.

 

1-2. 토큰 인증 방식

토큰 인증 방식은 유저가 로그인했을 때, 서버가 유저를 식별할 수 있는 Identifier (편의상 UID라 하자. 참고로 UID는 unique 해야함) 등을 토큰에 담아 반환하여, 이후 HTTP 요청마다 토큰을 검증하고 유저를 식별할 수 있는 방식이다. 세션/쿠키 방식과의 차이점은 세션 정보 등을 저장하고 쿠키의 세션 ID로 저장된 세션 정보를 불러오는 것과, 세션 정보를 저장하지 않고 로그인 시 발급한 토큰만으로 검증과 식별이 모두 가능하다는 것에 차이가 있다.

 

토큰 방식도 여러가지 (JWT, OAuth, SAML 등)가 있지만, 그 중에서도 대표적인 JWT 토큰을 예시로 들겠다. (열쇠 모양이 토큰이다.)

토큰 인증 방식. 세션/토큰과의 차이를 확실히 보여주기 위해 refreshToken은 위 사진에서 표현하진 않았다.

 

 

엥? 그럼 이론적으로 토큰만 탈취하면 다른 사람 계정으로 인증 가능한거 아님?

그렇다. 그러한 이슈를 해결하기 위한 추가적인 조치가 필요하다.

 

2. 차이점 & 장단점

두 인증 방식은 각각 장단점을 가지고 있다.

  세션/쿠키 인증 방식 토큰 인증 방식
상태 관리 쿠키 관리는 브라우저가 다 해줌 요청마다 보내줘야 함
서버 부하 세션 정보 저장으로 인해 대규모 트래픽에서
공간 낭비가 생길 수 있음
Refresh Token 말고는 저장하는 게 없기 때문에
확장성이 뛰어남
XSS 공격 매우 취약하나, httponly로 어느정도 커버 가능함 localStorage에 토큰을 저장할 경우 취약함
CSRF 공격 별도의 CSRF 보호 메커니즘이 없으면 취약함 localStorage에 저장하면 안전함

 

추가적으로 설명하자면, XSS와 CSRF 공격은 다음과 같다.

XSS (Cross Site Scripting)

보안이 취약한 웹사이트에 악의적인 스크립트를 넣어 사용자가 이 스크립트를 읽게 유도하여 유저의 정보를 탈취하는 공격

CSRF (Cross-site Request Forgery)

사용자가 악의적인 사이트로 들어오도록 유도하여 해커가 의도한 행위를 사용자 권한으로 서버에 요청을 보내는 공격

 

 

3. 그래서 뭘 쓰라는거임?

XSS 공격과 CSRF 공격 모두에게서 안전하기란 쉽지 않다.

JWT 토큰의 경우 localStorage에 토큰을 저장할 경우 CSRF 공격으로부터는 안전하지만 XSS 공격에는 취약해진다.

 

사실 토큰 인증 방식 + 공격에 대한 방어 기법을 여러가지로 조합하여 가장 안전한/적합한 방식을 찾는 것이 좋은데,

개인적으로는 Secure HttpOnly Cookie에 JWT 토큰을 담아 사용하는 것이 가장 안전한 것 같다.

 

이게 무슨 말이냐 하면, Cookie에는 2가지 옵션이 있다.

HttpOnly (Boolean)

true로 설정할 경우, 클라이언트에서 Javascript로 조회할 수 없게 된다. 다시말해 쿠키를 가로챌 수 없다.

Secure (Boolean)

true로 설정할 경우, 네트워크 감청으로 인한 쿠키 탈취를 막을 수 있다. 다만 이 경우에는 HTTPS를 적용해야 한다.

 

위 옵션을 모두 사용할 경우 토큰 탈취 (XSS)로부터 높은 저항성을 가지게 된다.

여기에 토큰 인증 방식까지 더한다면, CSRF 공격으로부터 자유로워진다.

예를 들면, 로그인할 때 서버에서 Set-Cookie에 AccessToken을 담아 보내면, 클라이언트 (브라우저)에서는 XSS 공격을 받지 않으면서도 인증 정보를 안전하게 서버에 전달할 수 있다.

 

물론 이 토큰에 유효 기간까지 적용한다면 공격에 매우 안전한 인증 방식이 될 것이다.

 

 

4. Reference

https://cjw-awdsd.tistory.com/48

https://jhbljs92.tistory.com/entry/1-JWT-%ED%86%A0%ED%81%B0-%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98-%ED%86%A0%ED%81%B0