0. 글 작성 배경
쿠키, 세션, JWT는 모두 프로젝트를 만들면서 사용해본 경험이 있긴한데 정확히 어떠할 때 사용해야 할 지 모른채 사용을 했었다. 앞으로는 어떨 때 사용할 지 정확히 하기 위해 글을 작성했다.
1. Cookie

1-1. 정의
- 클라이언트와 서버를 이어주는 매개체
- 서버에서 생성, 브라우저에 저장됨
- 클라이언트에서 서버로 요청을 보낼 때 항상 함께 전송된다
- stateless한 HTTP요청을 stateful하게 유지하기 위한 기술
1-2. 등장 배경(로그인 유지 등)
- 웹 서비스를 개발하다 보면 여러 페이지(또는 요청)에 걸쳐서 상태를 유지해야 하는 경우가 발생한다. 만약 유지를 못한다고 하면, HTTP요청을 보낼 때마다 다시 로그인을 해야 하는 수고로움이 발생한다.
- 이를 해결 할 수 있는 방법은 사용자의 정보를 쿠키에 담아서 필요할 때 꺼내쓰는 것이다.
- 예를 들어, 사용자가 로그인을 하면 로그인 정보를 쿠키에 담아서 이후 요청을 보낼 때마다 로그인을 해야 했던 수고로움을 없앨 수 있다.
1-3. 문제점
- 쿠키는 사용자가 입력한 값(ID, PWD 등)이 웹 브라우저에 그대로 노출된다는 점에서 보안 상으로 취약하다
- 용량이 4KB로 제한되어 많은 데이터를 담을 수 없다
2. Cookie + Session
2-1. 정의
- 세션을 이용하면 사용자가 입력한 값을 웹 브라우저에 고유한 식별자로만 볼 수 있고, 실질적인 데이터는 서버에 식별자 파일로 저장된다. 즉, 쿠키처럼 서버가 보내는 중요 정보를 웹 브라우저에 남기는 일은 없다!
- 서버로 요청을 보낼 때마다 쿠키가 함께 전송되는데, 쿠키에는 세션아이디가 저장되어 있어 서버는 세션저장소에 세션 ID가 있는지 확인하고, 사용자가 누구인지를 식별할 수 있다.
- 세션 ID가 존재하면 사용자를 인증한 후 해당 요청을 처리할 수 있고, 없다면 401에러를 발생한다.
2-2. 등장 배경(서버 성능 향상)
- 쿠키의 처음 등장 당시에는 하드웨어 사양이 그닥 좋지 않았기 때문에 서버에 많은 데이터를 저장할 수가 없었다. 그래서 쿠키라는 데이터 형식으로 브라우저에 저장하게 하였던 것이다
- 하지만 시간이 지남에 따라 서버 성능도 증가했고 하드웨어의 비용이 감소했다
- 또, 쿠키의 보안 이슈도 있었는데 이를 해결하기 위해 중요 데이터는 서버에 저장하는 방식(세션)으로 발전하였다.
2.3 문제점
- Session ID, Cookie 등이 탈취된다면 세션 저장소를 전부 삭제해서 정보유출을 막을 수 있지만, 탈취당하지 않은 정상적인 사용자들도 모두 재인증을 해야 하는 번거로움이 발생한다.
- 무엇보다 http의 가장 큰 특징 중 하나인 stateless를 위반한다는 것이다. 왜냐하면 서버는 클라이언트의 상태를 저장하지 않아야 하는데 세션저장소라는 곳을 통해 클라이언트의 상태를 저장하기 때문에 서버가 stateful하게 된다.
- 이것이 왜 문제인가 싶을수도 있지만, 만약 서버를 스케일아웃해야 한다면 문제가 된다. 1번 서버에 로그인한 사용자가 다른 2번 서버로 요청을 보내면, 2번 서버에는 로그인한 상태정보가 없기 때문에 다시 로그인을 해야 한다.
2.4 문제점 해결
세션 클러스터링
스티키 세션
JWT
3. JWT
Json Web Token(JWT)은 유저가 로그인을 할 때 유저를 식별하기 위해 사용하는 일종의 "인증 티켓" 같은 것이다
JWT인증 방식이든, 서버기반 인증방식이든 지속적인 인증이 필요한 이유
HTTP는 stateless 프로토콜이며, 데이터를 전송하기 위해 사용된다. 클라이언트와 서버 사이를 연결시켜주는 매개체다. 원래는 웹 브라우저와 웹 서버 사이를 연결시켜 주기 위해 만들어졌다. HTTP프로토콜이 stateless하다는 것은, 어떤 유저가 로그인을 해서 인증을 받은 후, 다음 요청을 보내면 컴퓨터는 우리가 누구인지 알지 못한다. 다시 인증을 받아야 한다. 그렇기 때문에 우리가 누구인지 항상 알 수 있는 어떠한 지표가 필요한 것이다. 처음에 등장한 방식이 서버기반 인증 방식!
JWT 인증 방식 vs (전통적인)서버기반 인증 방식
로그인을 하면 일어나는 과정을 살펴보자 (전통적인 서버인증 방식)
유저가 로그인을 하면, 서버는 세션을 생성해서 서버메모리에 세션정보를 담는다. 이 세션은 세션아이디라는 것을 갖고 있고, 이 세션은 쿠키에 저장이 되어서 유저가 사이트에서 활동을 하는 동안 클라이언트의 브라우저에 저장되어 있다. 매번 유저가 요청을 보낼 때마다 쿠키는 함께 전송이 된다. 서버에서는 매번 이 쿠키에 담겨있는 세션 정보를 가지고 서버에 담겨있는 세션정보와 비교해서 판별할 수 있다.
유저가 로그아웃을 하면, 세션정보는 DB와 서버메모리에서 모두 삭제된다.
따라서 한마디로 전통적인 서버인증 방식은 유저가 로그인을 했을 때, 유저의 정보를 서버에 저장을 해놓는 것이다.
그런데 이것의 문제점은 뭘까?
서버기반 인증 방식의 문제점
-
서버 부하
유저가 인증을 받을 때마다 서버의 (메모리) 어디선가에서 항상 저장이 되어야 하고 유저가 많아지면 서버 부하가 일어날 수 있다.
-
CORS 문제
AJAX 요청을 해서 다른 도메인끼리 요청과 응답을 송수신할 수 있는데 이때 forbidden 요청이 일어날 수 있다.
-
CSRF 문제. Cross-site request forgery.
JWT의 등장
유저가 로그인을 해서 인증 요청을 하면, 서버에서 json 형식의 암호화된 토큰을 만들어서 클라이언트한테 보내고 이를 jwt라고 한다. 생성한 토큰은 HTTP 통신을 할 때 Authorization이라는 key의 value로 사용된다. (일반적으로 value에는 Bearer이 앞에 붙음)
클라이언트가 토큰을 받으면 유저가 인증이 됐다는 의미이고, 그 이후부터 유저는 원하는 활동을 할 수가 있다. jwt는 클라이언트에서는 localStorage에 저장되고 유저가 서버에 있는 데이터에 대한 어떠한 요청을 보낼 때마다 함께 전송된다. 서버에서는 jwt가 유효한지 아닌지 검증을 하고, 유효하면 데이터를 프론트로 보내고 아니면 요청을 무시한다.
로그아웃을 할 시에는 로컬 스토리지에 저장된 jwt 데이터를 제거합니다. (실제 서비스의 경우에는 로그아웃 시, 사용했던 토큰을 블랙리스트라는 DB 테이블에 넣어 해당 토큰의 접근을 막는 작업을 해줘야 함)