[WEB 개발 기초] 쿠키/세션/토큰의 기초를 공부해보자.

이민선(Jasmine)·2023년 5월 10일
1

WEB 개발 기초

목록 보기
5/7
post-thumbnail

음 그렇구나 ~ 하고 뒤돌아서면 헷갈리는 개념인 쿠키/세션/토큰의 개념적 차이에 대해 기록하고 두고두고 봐야겠다는 생각이 들었다.

원래 지난 포스팅에서 HTTP 프로토콜의 특징 4가지 중에 HTTP 메시지만 이번에 별도로 포스팅을 하기로 했었다. 근데 왜 갑자기 딴 주제? HTTP 헤더에 담는 쿠키 정보에 대해 포스팅하려면 쿠키/세션/토큰을 먼저 명확히 알고 나서 다루는 게 나을 것 같다는 생각이 들었기 때문이다.

그래서 이번 포스팅에서는 쿠키/세션/토큰의 공통적인 역할과 차이점에 대해 알아보려고 한다.

그 전에 인증(authentication)과 인가(authorization)의 차이를 먼저 알아야 한다.

인증? 인가? 비슷한 말 같은데 뭐가 다를까?

쉽게 정리해보자면 인증은 "당신 누구야?"이고, 인가는 "이 웹 서비스(나의 메일함, 노래 듣기 등)를 당신이 할 수 있는가?"이다.

만약 멜론 유저가 아이디와 비밀번호를 입력하면 서버로부터 인증(authentication)을 받는 것이고, 로그인 인증 완료 후 나만의 음악 서랍, 노래 검색 목록, 노래 1분만 듣고 컷 당하지 않기 등의 서비스를 이용하려면 인가(authorization)를 받아야 하는 것이다.

인증


로그인을 통해 사용자가 신원(identity)을 증명하는 것이다. 나의 멋진 아이디~~~와 비밀번호로 HTTP POST 요청을 보내는 사진이다.

인가


인증된 사용자가 특정한 작업을 수행하거나 특정 자원에 접근할 수 있는 권한을 갖는지 확인하는 것이다. 나는 멜론에 로그인을 했기 때문에 최근 들은 음악 리스트를 볼 수 있는 권한이 주어진다.

1. 쿠키

사용자가 어느 웹페이지에 들어가서 로그인을 하거나, 장바구니에 물품을 추가하는 등 새로운 상태가 생겼다고 가정해보자. 이 때 사용자가 로그인을 하고 마이뮤직에 들어가도 로그인이라는 상태는 유지되어야 하고, 샴푸를 장바구니에 추가했다가 커피를 구경하러 가도 장바구니의 상태는 유지되어야 한다.

그런데 여기서 의문이 생긴다. HTTP 프로토콜은 무상태적이라며?
무상태성은 사실 이론에 불과한거였던거야?? 그런거야???

놀랍게도 서버의 무상태성을 유지하면서 사용자의 상태가 유지될 수 있도록 하는 방법이 있는데, 그 중 하나가 쿠키이다. 냬가 만든 뀨끼~~


사진 보니까 배고파져서 덜 맛있어보이는 걸로 가져옴;;

그래서 서버의 무상태성을 유지하면서 사용자의 상태를 유지하는 건 어떻게 하는걸까? 동작 원리를 살펴보자.

쿠키의 동작 원리

  1. 유저가 인증 받으려고 로그인을 하거나 (또는 장바구니에 물건을 추가하거나) post 요청을 함
  2. 서버가 아이디와 비밀번호가 유효한지 체크한 다음(또는 DB에 장바구니 상태를 갱신) 클라이언트에게 쿠키를 전송해줌.(HTTP 헤더에는 set-cookie 속성을 기재)
  3. 브라우저에 쿠키를 가지고 있는 유저는 다른 페이지로 이동할 때마다 서버에 쿠키를 전송. 나 인증 받은 사람이야! 이 쿠키를 봐!
  4. 서버: 내가 저걸 보내줬었다고? ㅇㅋ. 넌 자격이 있다.

중요한 것은 서버로 부터 전송받은 쿠키를 클라이언트 측인 브라우저에 가지고 있는다는 것이다. 이렇게 다른 페이지로 이동하는 등 새로운 요청을 하더라도 쿠키에 클라이언트의 상태가 저장되면, 서버의 무상태성을 유지하면서도 클라이언트의 상태를 저장할 수 있는 것이다.

위에서 인증과 장바구니를 예로 들어보았는데, 쿠키에는 사용자가 선호하는 언어가 한국어인지 영어인지 등등 유저의 다양한 상태를 저장할 수 있다.

그런데 쿠키에는 허점이 있다. XSS 공격 위험이 있다는 것!

XSS(Cross-Site Scripting) 공격은 스크립트에 악성코드를 심어서 민감한 정보를 탈취하는 것이다. 쿠키 방식에서는 사용자의 인증정보가 클라이언트 측에 있기 때문에 쿠키를 탈취하여 악성코드를 심고 위조된 쿠키를 가지고 서버에 민감한 정보를 요청할 수도 있다. 서버는 요청에 쿠키가 실려져 왔는지 확인하고 인가하기 때문에, 악의적인 요청인지 확인하기 어렵다.

지금까지 이해가 가장 수월할 것 같은 인증 정보로 예시를 들기는 했지만, 쿠키는 클라이언트 측에 정보가 저장되어 보안상 허점이 있기 때문에 인증과 같은 중요한 정보보다는 조작되어도 크케 문제가 일어나지 않는 정보 저장(장바구니, 언어 설정 등) 위주로 사용된다. 로컬 스토리지나 세션 스토리지로 대표되는 웹 스토리지 API를 사용하면 매 요청 시마다 서버에게 쿠키를 전송할 필요가 없기 때문에 쿠키를 탈취당할 일이 그나마 줄어든다고 한다. 물론 여전히 XSS 공격에서 자유롭지는 않음.

세션 방식은 이러한 XSS 공격을 완화할 수 있는 방법 중 하나이다. 아래에서 살펴보겠지만, 클라이언트 측이 아니라 서버에 중요 정보를 꽁꽁 숨겨놓기 때문이다.

2. 세션

쿠키 방식에서는 사용자가 인증에 성공하면 서버에서 쿠키를 전송해준다고 했었는데, 세션 방식에서는 쿠키에 세션 ID라는 것을 넣어서 보내준다. 즉, 쿠키를 보내는 것 자체는 쿠키 방식과 동일하지만, 쿠키는 그저 매개체일 뿐이고 진짜 알맹이는 세션ID라는 점에서 차이가 있다.

세션의 동작 원리

  1. 유저가 인증 받으려고 로그인을 함.
  2. 서버가 아이디와 비밀번호가 유효한지 체크한 다음 세션DB에 유저를 생성하고 클라이언트에게 "세션ID가 들어있는" 쿠키를 전송해줌.
  3. 브라우저에 쿠키를 가지고 있는 유저는 다른 페이지로 이동할 때마다 서버에 세션ID를 전송. 나 인증 받은 사람이야! 이 세션ID를 봐!
  4. 서버: 내가 저걸 보내줬었다고? 오 DB를 확인해보니 너의 세션ID 유효하군. ㅇㅋ. 넌 자격이 있다.

쿠키 방식에서는 상태를 클라이언트 측에서 브라우저에 저장한다고 했었는데, 세션 방식에서는 상태 정보를 서버 측에서 가지고 있기 때문에 훨씬 안전하다. 그래서 인증을 구현하기에 적합한 방식이다. 이를 session-based-authentication이라고 한다.

이렇게 쿠키에 비해 보안상의 장점이 있기는 하지만, 유저의 수가 늘어나면 이에 비례하여 DB 리소스가 많이 필요해진다는 단점이 손꼽힌다. DB에 사용자 정보를 하고, 클라이언트 측에서 인가 받기 위해 세션ID를 보내올 때 유효한지 확인하는 과정을 거쳐야 하기 때문이다.

DB 리소스가 좀 덜 필요한 방식으로 인증을 구현할 수는 없을까?
토큰 방식이 있쥐! 아래에서 토큰 방식을 살펴보자.

3. 토큰

사용자 상태를 tracking하기 위해 세션Id를 발급해주는 세션 방식에서와 달리, 토큰 방식에서는 인증에 대한 정보를 토큰에 담아 발급해준다. 가장 큰 차이는 사용자 인증 정보가 토큰에 포함되어 있다는 점과 사용자가 지니고 있다는 점이다. 이 토큰은 마치 신분증과 비슷한 역할을 한다.

그리고 특정 리소스에 대한 접근 권한이 필요할 때는 쿠키? 아니아니~ 세션 Id? 아니아니~ 토큰을 서버에게 보내는 것이다.

토큰의 동작 원리

  1. 클라이언트가 서버에게 로그인 요청을 보내면 서버는 유효한 사용자인지 확인하고, 클라이언트에게 JWT(JSON Web Token)을 발급해준다. 마치 신분증을 발급 받는 것과 비슷하다.
  2. 로그인 인증 후 다른 리소스 접근 필요할 때 발급 받은 JWT를 헤더에 담아 전송.
  3. 서버는 요청을 받으면 토큰이 유효한지 검증하고, 유효할 경우에만 요청에 대한 처리를 진행한다.

세션 방식과 달리 세션 DB가 따로 필요하지 않다는 특징이 있다. 서버 측에서 상태를 유지하지 않고 토큰만 확인하기 때문이다. 그래서 아무래도 세션ID보다는 토큰에 정보가 뭐가 더 많이 담겨있다.

  • 사용자ID
  • 사용자의 권한
  • 발행자(토큰을 발급해준 서버의 정보)
  • 토큰 만료 시간
  • 서명: 토큰이 유효한지 검증

세션 방식에서는 심플하게 세션ID만 적혀있어도, 세션DB에 있는 유저 정보와 비교하여 유효한지 검사하는 방식이지만, 토큰 방식에서는 토큰만 보고 판단해야 하기 때문이다.
다만 토큰도 쿠키처럼 탈취당하면 악성 유저가 위장하여 서버에 요청을 보낼 위험이 있기 때문에, 토큰의 만료기간을 적절하게 설정하는 것이 중요하다.

세션과 토큰의 장단점 비교

1. 보안성 (세션 방식 승)

세션 방식에서는 세션 ID가 서버 측에서 관리되기 때문에 상대적으로 안전하다. 반면 토큰은 탈취당하면 악용될 가능성이 있기 때문에 덜 안전하다. 신분증을 누가 훔쳐가는 것과 비슷한 맥락이다.

2. 확장성 (토큰 방식 승)

세션 방식은 서버 측에서 상태를 유지하기 때문에 stateful한 방식이지만, 토큰 방식은 클라이언트 측에서 상태를 유지하기 때문에 stateless한 방식이다. 따라서 로드 밸런싱 기술 적용이 용이하고 확장성이 좋다.

💡 로드 밸런싱?? 그게 뭐죠?
서버에 들어오는 부하를 분산시켜 처리하는 기술이다. 클라이언트에서 들어오는 요청을 클러스터에 있는 서버들 중 하나에 할당하는 역할을 한다. 단일 서버에서 처리하기에 너무 많은 부하가 발생할 경우에도, 서비스의 안정성과 가용성을 유지할 수 있다.

같은 맥락에서, 세션 방식에서는 서버가 유저의 정보를 세션DB에 저장해야 하기 때문에 DB리소스가 많이 소요된다. 반면 토큰 방식에서는 토큰 자체만 보고 유효한지 판단하는 메커니즘이므로 DB리소스가 상대적으로 덜 소요된다.

3. 처리 속도 (토큰 방식 승)

세션 방식에서는 클라이언트의 요청이 들어올 때마다 세션 정보를 조회하고 업데이트하고 언제 다해? 상대적으로 느리다.
토큰 방식에서는 토큰만 확인하면 되는데 서버에서 별도로 상태 정보를 조회하고 업데이트하는 절차가 필요없다. 상대적으로 빠르다.

따라서 상황에 따라 적합한 방식이 다를 수 있기 때문에 보안성, 확장성, 처리 속도 등의 요소를 고려하여 세션 방식과 토큰 방식 중 선택을 내린다고 한다.

여기까쥐~ 쿠키/세션/토큰에 대해 기초적인 공부를 해보았다. 정리하기 전에는 뒤죽박죽이었는데 이제야 좀 체계가 머릿속에 잡힌다. 이제 HTTP 메시지 포스팅할 때 인증, 쿠키 관련 헤더 정보도 좀 더 명확하게 쓸 수 있을 것 같다! 이 포스팅은 아주 기초만 다룬 것이기 때문에 새로 알게 된 지식이 있으면 또 업데이트 하러 돌아와야겠다. 다음 시간에는 한 타임 미뤘던 HTTP 메시지 포스팅! 씨유쑨

profile
기록에 진심인 개발자 🌿

0개의 댓글