stateless, stateful
stateless, stateful
- stateless : 서버에서 HTTP와 같은 client의 이전 상태를 기록하지 않는 접속
- stateful : 서버에서 client의 이전 상태를 기록
- REST의 개념에서는 각각의 요청은 독립적인 stateless 방식이며 이것은 client가 상태정보를 모두 관리할 책임이 있다는 뜻이다
- stateless는 caching, load balancing, scale out 이 장점이지만, 매 요청마다 상태 정보를 전달 받아야 하기 때문에 네트워크 자원을 소모하며, 서버는 정보를 처리하기 위한 작업이 필요하다
- HTTP 프로토콜은 요청에 다른 응답을 받으면 연결이 끊어지고, 통신이 종료되면 어떠한 상태도 남지 않는다
- 따라서 로그인 후 다시 웹 페이지에 접근하면 로그인 상태가 유지되지 않는 문제점이 있다.
- HTTP 프로토콜의 인증 문제를 해결하기 위해 사용하는 방법으로 세션과 쿠기를 사용한다
세션
- 사용자가 서버에 로그인 request
- 서버는 request가 들어오면 DB를 쿼리하여 사용자 검증, 유효할 경우 고유한 ID 값을 부여하고 세션 저장소에서 저장한다. 이와 연결되는 세션 ID를 생성하여 response header에 포함시켜 response 한다
- 사용자는 서버에서 해당 세션ID를 받아 쿠키에 저장 한 후 제한된 요청에 접근할 때 마다 쿠키를 request header에 포함시켜 내보낸다
- 서버에서는 쿠키를 받아 세션 저장소에서 검증한 후 요청에 해당하는 데이터를 반환한다
세션의 특징
- 쿠키(서버에 저장된 세션에 접근하기 위한 세션ID)가 HTTP 요청 중 노출되어도 쿠키 자체에 중요한 정보는 담겨있지 않다
- 하지만 쿠키 자체를 훔쳐 세션에 접근하여 중요한 정보를 빼낼 수 있다.
- 이를 막기 위해 세션에 유효시간을 넣거나 HTTPS를 사용하여 요청을 훔쳐도 그 안의 정보를 보기 힘들게 한다
- 쿠키를 통해 세션에 접근하면 세션ID로 사용자를 구분할 수 있으므로 일일히 사용자 정보를 확인할 필요가 없다
- 서버에 세션을 저장하기 때문에 사용자 수가 많아지면 서버의 부담이 늘어난다, 또한 서버의 확장성이 나빠진다
- 서버의 사양 업그레이드 뿐만 아니라, 늘어나는 트래픽을 감당하기 위해서 여러 프로세스를 돌리거나 여러 대의 컴퓨터를 추가하는 것이 어렵다
- 세션은 서버에서 가진 정보이며 쿠키는 사용자에게 발급된 세션을 열기 위한 ID이다
- 인증의 책임을 서버에서 가지지 위해 사용자에게서 쿠키를 받아 세션을 가져온다
- client의 HTTP 요청이 탈튀 당하여 쿠키가 해킹당한다면(세션 하이재킹 공격) 서버는 사용자를 오인하여 정보를 제공한다
- 이것을 막기 위해 HTTPS 를 사용하거나 세션에 유효기간을 건다
- 쿠키는 단일 도메인 및 서브도메인에서만 작동하도록 설계되어 있어 여러 도메인에서 관리하기 번거롭다.
토큰
- 세션 기반 인증과는 달리 서버의 토큰을 이용하여 인증을 수행하는 방법
- 세션 기반 인증의 stateful 서버는 클라이언트로부터 요청이 있을 때 마다 클라이언트의 상태를 유지한다.
- 사용자가 로그인하여 인증을 요청하면 stateful 서버는 인증에 성공하였을 때 결과(세션)을 메모리 또는 DB에 유지하기 때문에 서버에 부하가 발생할 수 있다
- 하지만 토큰 기반 인증은 stateless 서버를 사용하며 상태 정보를 유지하지 않는다
- 서버가 전달받은 토큰을 검증만 하면 되기 때문에 서버의 부담을 줄이고 서비스의 확장성을 높일 수 있다
- 사용자가 로그인 request
- 서버는 request가 들어오면 사용자 검증을 통해 유효성을 확인하고 통과하면 토큰을 response와 반환한다
- 클라이언트는 토큰을 저장, 서버에 요청 시 토큰을 request header에 담아 서버에 요청
- 서버는 토큰을 검증 후, 요청에 응답
토큰의 특징
1. 모바일 앱 사용에 편리
- 세션 기반 인증을 사용하면 쿠키 매니저를 따로 관리해야 한다.
- 하지만 토큰을 사용하게 되면 웹 요청 API 헤더에 넣어서 사용을 하기 때문에 쿠키 매니저가 필요하지 않다.
2. CSRF 방지
- 세션을 쿠키에 저장하여 사용하면
- 사용자가 사이트를 벗어나도 이미 쿠키가 사용자 정보를 가지고 있기 때문에 공격자에게 노출 될 위험이 있다.
- 공격자가 임의로 다른 URL을 유도하여 비밀번호를 바꾸거나 회원 탈퇴를 할 경우 쿠키가 있기 때문에 서버는 요청을 신뢰하고 작업을 수행한다
- 이러한 문제를 해결하기 위해 탈퇴 시 비밀번호를 한 번 더 요구하거나, 토큰과 같은 credential을 포함한다
- 하지만 토큰을 사용하면
- 헤더 내 토큰이 포함되어 CSRF를 방지할 수 있다
3. 서버 확장 문제 해결
- 여러개의 서버에서 한 세션이 첫 번째 서버에 생성되었다고 가정하면
- 새로운 요청이 발생하고 그 요청이 다른 서버에 전달되면 해당 서버에는 세션 정보가 없으므로 unauthorized 응답을 받는다
- stick세션(같은 서버에 세션을 계속 연결시키는 방식)을 사용하여 해결할 수 있다
- 하지만 토큰을 사용하면
- 요청 토큰은 모든 요청, 모든 서버가 가로채기 때문에 자연스럽게 이러한 문제가 해결된다
토큰 방식의 문제
- sateless한 토큰의 특성 때문에 토큰을 강제로 만료할 수 없다
- 토큰이 공격자에게 탈취되었다고 가정하면,
- 공겨자는 토큰이 만료될 때 까지 서버에 요청을 할 수 있다.
- 토큰 인증 방식의 단점을 보완하기 위해 토큰의 타입을 리프레시 토큰과 엑세스 토큰으로 나누어 사용하는 방식의 JWT 토큰을 사용하게 된다
JWT
- Json Web Token은 인증헤더 내 사용되는 토큰 포멧이다.
- 토큰은 base64로 인코딩한 string으로 이루어진다
- 토큰은 두 개의 시스템끼리 안전한 방법으로 통신할 수 있도록 설계하는 것을 도와준다
JWT 장점
- 계정 서버와 API 서버가 분리되어 있을 때 API 서버가 계정 서버에게 토큰의 유효성 여부를 물어보지 않고도 스스로 판단할 수 있다
- Access Token은 단순하게 자원에 접근하는 Access Token이 아니라, 권한/인증에 대한 Token을 말한다
- Refresh Token은 Access Token과 똑같은 형태의 JWT이며 Access Token의 탈취 문제를 해결하기 위해 발급하는 토큰이다
- 처음의 로그인을 완료할 때 Access Token과 함께 발급되는 Refresh Token은 긴 유효시간을 가지면서 Access Token이 만료되었을 때 새로 발급해주는 열쇠가 된다
토큰과 세션의 차이
- stateful 서버
- 클라이언트에게 요청을 받을 때 마다 클라이언트의 상태를 계속해서 유지하고 이 정보를 서비스 제공에 이용한다.
- 예를들어
- 세션을 유지하는 웹 서버가 있다
- 로그인을 하면 세션에 로그인이 되었다고 저장을 하고
- 서비스를 제공할 때 해당 데이터를 사용한다
- 세션은 서버의 메모리 또는 DB에 저장한다
- stateless 서버
- 상태를 유지하지 않는다
- 서버는 클라이언트 측에서 들어오는 요청만으로 작업을 처리한다
- 클라이언트와 서버의 연결고리가 없기 때문에 서버의 확장성이 높아진다
- 클라이언트가 고유 식별자를 가지고, 해당 식별자를 바탕으로 인증을 처리한다
- 세션이 식별자에 대한 정보를 서버에 저장한다고 하지만 일부는 클라이언트에 저장한다. 보통은 쿠키로 저장한다
- 세션은 그 식별자가 HTTP session에 한정된다는 점에서 토큰보다는 제한된 범위의 활용성을 가진다
- 큰 흐름에서 세션은 기존의 웹 서비스에서 HTTP session을 기준으로 정보를 처리하였다
- 토큰은 고유 식별자로 토큰을 만들어서 클라이언트에게 전달하는 방식으로 처리되어왔다
- 따라서 토큰만 전달이 되면 다양한 포맷(json, xml) 구분없이 stateless로 폭 넓게 사용이 될 수 있다.