웹 서버는 사용자를 구분해야합니다.
사용자를 구분해야 사용자에 따라 적절한 서비스를 제공할 수 있기 때문이죠
사용자를 구분하려면 어떻게 해야 할 까요??
그 전에 인증과 인가에 대해서 간단하게 알아봅시다.
인증이란 현재 사용자가 누구인지 검증하는 과정입니다.
즉, 서비스에 접근할 수 있는 사용자인지를 구분하는 과정입니다.
ID/PW를 사용해서 로그인 라는 과정을 인증 과정이라고 생각하면 편합니다.
대표적인 회원제 서비스인 에브리타임을 예를 들어 보겠습니다.
여기 에브리타임 서비스와 두 명의 사용자 있습니다.
한 명은 대학교 학생이라, 학교 메일을 통해 인증을 받은 사용자이고,
다른 한 명은 인증을 하지 않아서 인증되지 않은 익명 사용자(Anonymous User) 입니다.
이 두 명이 각각 에브리타임 서비스에 접근하려고 하면 어떻게 될까요??
인증이 된 학생 유저는 에브리타임 서비스를 이용할 수 있지만, 익명 사용자는 사용할 수 없습니다.
회원제 서비스에서 아무나 들어오는 것은 비즈니스 로직에 부합하지 않으니깐요.
인가는 사용자가 특정 컨텐츠에 접근을 시도할 때, 적절한 권한을 가지고 있는지에 대해 검증을 하는 과정입니다.
인증을 받은 사용자라고 하더라도 모든 사용자에게 동일한 컨텐츠를 보여주면 안됩니다.
사용자들은 각자의 권한이 전부 다르기 때문이죠.
인증을 받은 두 명의 사용자가 있다고 해보겠습니다.
그리고 두 명의 사용자는 학교가 다릅니다.
그렇다면 두 명은 각각 본인 학교의 에브리타임에만 접속할 수 있어야만 합니다
만약 B 대학의 학생이 A 대학의 에브리타임에 접속을 시도하면, 인가되지 않은 사용자이기 때문에
에브리 타임은 접근을 거부할 겁니다.
권한이 올바르지 않기 때문이죠
이렇듯 서버는 현재 접속을 시도하는 사용자를 검증해서, 접속을 차단할 것인지, 어떤 정보를 보여줄 것인지 결정해야 합니다.
그런데 http 프로토콜은 상태를 저장하지 않습니다. 다른 말로 stateless 하다고 하죠
그러면 클라이언트와 서버 사이의 인증 및 인가, 권한 등에 대한 정보를 어떻게 공유할까요???
서로 아무런 공유가 되지 않으면 모든 작업이 의미가 없을 텐데 말이죠...
그래서 우리는 사용자에 대한 정보를 서버와 클라이언트 사이에서 서로 주고 받을 필요가 생겼습니다.
그리고 이러한 과정에서 쿠키, 세션, 토큰 등이 사용 되죠.
내가 만든 쿠키~
HTTP 쿠키(HTTP cookie)란 하이퍼 텍스트의 기록서(HTTP)의 일종으로서 인터넷 사용자가 어떠한 웹사이트를 방문할 경우 사용자의 웹 브라우저를 통해 인터넷 사용자의 컴퓨터나 다른 기기에 설치되는 작은 기록 정보 파일을 일컫는다
쿠키는 브라우저에 저장되는 텍스트입니다.
즉 클라이언트에서 관리하는 정보라고 할 수 있죠.
쿠키는 서버에서 만들어 진 후 사용자에게 전달 되고, 추후 사용자가 다시 요청을 보낼 때 쿠키와 같이 보내게 됩니다.
쿠키는 주로 3가지 목적으로 사용됩니다.
로그인, 장바구니, 게임 점수 기록과 등과 같은 서버가 기억해야 할 정보 기록
사용자가 설정한 정보, 테마 등의 정보 기록
사용자의 행위를 기록 및 분석하기 위해 사용자의 정보를 기록
쿠키는 다른 쿠키를 저장할 공간을 위해 또는 서비스 제공측의 비즈니스 로직에 의해 TTL(Time To Live)가 정해져 있습니다.
사용자의 장바구니를 쿠키에 보관하는 웹사이트에서 쇼핑을 할 때,
크롬 웹 브라우저에서 바나나를 장바구니에 보관했지만.
해당 사이트를 파이어폭스로 다시 들어가면 장바구니에 아무런 품목이 존재하지 않는다는 뜻입니다.
위의 장바구니 상황에서 장바구니에 담은 품목이 계속 커지게 되면, 쿠키의 크키가 커지게 됩니다.
그리고 이는 http 요청의 크기가 커지게 됩니다.
쿠키는 다음과 같은 과정으로 생성됩니다.
1. 클라이언트는 서버에 http 요청을 보낸다
2. 서버는 1.
의 요청에 대한 응답을 클라이언트로 보낸다
이 때, http 응답의 헤더 부분에 쿠키를 생성토록 하는 Set-Cookie를 포함해서 전송한다
3. 클라이언트는 응답을 기반으로 쿠키를 생성한다.
4. 클라이언트가 서버로 요청을 다시 보낼 때, 이번에는 쿠키를 헤더에 포함해서 보낸다
5. 서버는 요청의 헤더의 쿠키를 기반으로 사용자를 식별한다.
세션은 서버에 저장되는 클라이언트에 대한 정보입니다.
그리고 클라이언트는 쿠키를 통해 본인의 세션 ID를 저장하죠
세션이 생성되고 사용되는 메커니즘은 다음과 같습니다.
정확히는 서버의 로컬 스토리지안에 저장됩니다.
이는 서비스가 싱글 서버로 운영될 때는 문제가 되지 않습니다. 서버 안에 모든 세션 정보가 다 저장되어 있으니깐요
하지만 서비스가 인기가 많아지고, Scale-Up으로는 더 이상 운영상의 요구사항을 감당하기 힘들 때가 올 것입니다.
그러면 Scale-Out, 서버를 늘려야 하죠
이러면 문제가 생깁니다.
세션은 서버의 로컬 스토리지 안에 저장되는데, 사용자가 로드 밸런싱에 의해 다른 서버로 리다이렉팅 되면, 해당 서버의 로컬 스토리지안에는 사용자의 세션 정보가 없으니깐요
로드 밸런서는 부하를 분산했을 뿐인데....
사용자는 본인의 세션 정보가 쓸모 없어졌다
이 문제의 해결 방법은 제 이전 포스팅 - 멀티 서버 환경에서 세션을 유지하는 방법을 참고해 주시면 감사하겠습니다.
세션의 정보는 서버에 저장됩니다.
그렇기 때문에 동시에 접속중인 사용자가 많아지면, 서버에 무리가 가겠죠!
그러면 서버는 서버대로 사용자의 세션을 유지하기 위해서 자원을 써야하니까요
클라이언트는 세션 ID를 쿠키에 저장합니다.
하지만 쿠키는 외부의 공격에 매우 취약합니다.
브라우저 안에 저장되어 있는 쿠키는 누가 뺏어간 뒤, 해당 세션 ID를 가지고 해커가 '나 인척'을 할 수 있습니다!!
토큰방식은 세션과는 다른 방식으로 인증 및 인가를 진행합니다.
클라이언트가 서버에 접속을 하면, 서버는 토큰을 발급한 뒤 클라이언트에게 넘겨줍니다.
클라언트는 로컬 스토리지에 잘 저장해 놓습니다.
그리고 클라이언트는 서버에 접근할 때 서버에 토큰을 넘겨주죠.
서버는 클라이언트로 부터 받은 토큰을 검증만 합니다!!
서버는 토큰을 저장하지 않죠.
만약 토큰이 유효한 토큰이면 사용자에게 알맞을 리소스를 리턴해 주면 되고, 아니면 접근을 차단합니다.
JSON 웹 토큰(JSON Web Token, JWT, "jot”1은 선택적 서명 및 선택적 암호화를 사용하여 데이터를 만들기 위한 인터넷 표준으로, 페이로드는 몇몇 클레임(claim) 표명(assert)을 처리하는 JSON을 보관하고 있다.
JWT는 다음과 같은 구조로 이루어져 있습니다.
{
"alg" : "HS256",
"typ" : "JWT"
}
헤더는 어떤 알고리즘을 사용할지 등의 정보를 포함하고 있습니다.
{
"loggedInAs" : "admin",
"iat" : 1422779638
}
HMAC-SHA256(
secret,
base64urlEncoding(header) + '.' +
base64urlEncoding(payload)
)
Access Token
이란 실질적으로 인증 및 인가 작업을 수행하는 토큰입니다.
이 녀석만 있으면 인증/인가 작업을 잘 수행할 수 있죠.
하지만 문제가 있습니다.
클라이언트가 로컬 스토리지에 잘 보관해서 탈취당하지 않으면 괜찮지만...
이 역시 클라이언트가 보관을 하기 때문에 언제든지 누군가가 탈취를 할 수 있고, 사이트에서 '나 인척' 행세를 할 수도 있죠..!!!
그렇기 때문에 Access Token
은 보통 유효 시간이 짧게 설정해 놓습니다.(30분 정도)
그런데 이렇게 하면 Access Token
이 빠르게 만료되고
만료 될 때마다 사용자는 재로그인을 해야합니다
이거는 진짜 귀찮겠죠
이에 대한 해결 방식으로 Refresh Token
이 등장합니다.
Refresh Token
은 Access Token
을 재발행하는 토큰입니다.
사용자는 처음에는 발급받은 Access Token
으로 서버의 리소스에 접근을 하다가 Access Token
가 만료가 되면 Refresh Token
을 사용해서 Access Token
을 새로 발급 받습니다.
때문에 Refresh Token
은 만료 시간이 꽤 긴 편입니다. (2주 정도)
그림으로 보면 다음과 같습니다!