웹은 기본적으로 과거의 상태를 유지하지 않는 무상태(Stateless) 연결입니다. 요청(Request)과 응답(Response) 을 하나의 단위로 처리하면서 기존 사용자에 대한 정보는 기억하지 않습니다.
무상태라는 특징으로 인해 기존의 방문자를 기억하기 위해서는 특별한 매커니즘을 사용하게 되는데, 세션(HttpSession) 이나 쿠키(Cookie)라는 존재를 이용하기도 하고, 특정한 문자(토큰, Token)을 사용하기도 합니다.
로그인 유지를 위한 모든 기능을 웹에서는 세션 트랙킹(Session Tracking) 이라고 합니다.
HTTP는 기본적으로 무상태이기 때문에, 과거의 요청 기록을 알 수가 없습니다.
HTTP가 무상태를 선택하게 된 가장 큰 이유는 적은 자원으로 여러 개의 요청(Request)을 처리할 수 있다는 장점이 있기 때문인데, 이 때문에 과거의 방문 기록을 추척할 수 있도록 하는 기법인 세션 트랙킹(Session Tracking)이라는 기법이 필요하게 되었습니다.
HTTP에서 세션 트래킹은 쿠키(Cookie)라는 것을 이용하게 되는데,
쿠키는 문자열로 만들어진 데이터의 조각으로써, 서버와 브라우저 사이에서 요청(Request)이나 응답(Response)시에 주고받은 형태로 사용되게 됩니다.
쿠키는 문자열로 되어 있는 정보로, 가장 기본적인 형태는 [이름(Name), 값(Value)] 의 구조로 이루어져 있습니다. (브라우저에서 F12(개발자 도구) 의 애플리케이션 탭에서 확인이 가능합니다.)
쿠키(Cookie) 는 클라이언트 측에 저장되는 작은 텍스트 파일로써, 서버는 클라이언트에게 응답(Response)할 때, 쿠키를 설정하여 클라이언트에게 세션ID를 저장하거나 기타 정보를 전달할 수 있습니다. 클라이언트는 이후 요청에서 쿠키를 서버로 다시 전송하여 세션을 유지하거나 추가 정보를 제공합니다.
세션과 쿠키는 보통 함께 사용되며, 세션ID를 쿠키에 저장하여 클라이언트가 다시 접속할 때 세션을 식별하고, 상태를 유지할 수 있게 됩니다. 이를 통해 웹 어플리케이션은 클라이언트의 상태를 추척하고, 사용자 별로 개별적인 경험을 제공할 수 있게 됩니다.
브라우저에서 최초로 서버를 호출하는 경우에, 해당 서버에서 발행된 쿠키가 존재하지 않는다면,
브라우저는 아무 것도 전송하지 않습니다.
서버에서는 응답(Response) 메세지를 보낼 때 브라우저에게 쿠키를 보내주게 됩니다.
(이 때, Set-Cookie 라는 HTTP 헤더를 이용합니다.
브라우저는 쿠키를 받은 후에 이에 대한 정보를 읽고, 파일 형태로 보관할 것인지, 혹은 메모리 상에서 처리를 진행할 것인지를 결정하게 됩니다.
(이 판단은 쿠키에 있는 유효기간을 보고 판단하게 됩니다.)
브라우저가 보관하고 있던 쿠키는 다음에 다시 브라우저가 서버에 요청(Request)할 때 HTTP 헤더에 Cookie 라는 헤더 이름과 함께 전달되게 됩니다.
(이 떄, 쿠키에는 경로(Path)를 지정할 수 있어서 해당 경로에 맞는 쿠키가 전송됩니다)
서버에서는 필요에 따라서 브라우저가 보낸 쿠키를 읽고, 사용하게 됩니다.
서버에서 쿠키를 발행하는 방법에는 대체적으로 2가지 방식이 존재합니다.
서버에서 자동으로 생성되는 쿠키
⇒ 응답 메세지를 작성할 때, 정해진 쿠키가 없는 경우에 자동으로 발행
(WAS에서 발행되며, 이름은 WAS마다 고유한 이름을 사용해서 쿠키를 생성하게 됩니다.)
개발자가 생성하는 쿠키
개발자가 생성하는 쿠키는, 서버에서 생성되는 쿠키과 다른 점들이 몇가지 존재합니다.
각각의 웹 어플리케이션을 생설할 때는 톰캣(서버)이 발행하는 쿠키들을 관리하기 위한 메모리 영역이 하나 더 생성되는데,
이 영역을 세션 저장소(Session Repository) 라고 합니다.
세션 저장소는 기본적으로 키(Key)와 값(Value)을 보관하는 구조입니다.
이 때, 키가 되는 역할을 하는 것이 톰캣에서 JSESSIONID 라는 쿠키의 값이 되게 됩니다.
서버에서는 브라우저가 가지는 JSESSIONID 쿠키의 값을 키(Key)로 보관하게 됩니다.
톰캣 내부의 세션 저장소는 발행된 쿠키들의 정보를 보관하는 역할을 하게 되는데, 문제는
새로운 JSESSIONID 쿠키가 만들어 질 때마다 메모리 공간을 차지해야 한다는 점 입니다.
이 문제를 해결하기 위해서 톰캣은 주기적으로 세션 저장소를 조사하면서, 더 이상 사용하지 않는 값들을 정리하는 방식으로 동작합니다.
코드상에서 getSession()이라는 메서드를 실행하게 되면, 톰캣에서는 JSESSIONID 이름의 쿠키가
요청(Request)시에 존재했었는지를 확인하고, 없었다면 새로운 값을 만들어 세션 저장소에 보관하게 됩니다.
예를 들어 3개의 브라우저가 처음으로 세션이 필요한 경로를 요청했다고 가정했을 때,
각 JSESSIONID의 값이 A1234, B1111, C3333 이라고 가정한다면
| 세션 컨텍스트 OR 세션 저장소? | ||||
|---|---|---|---|---|
| (JSESSIONID) | (Key) | (Value) | ||
| A1234 | ⇒ | Login 정보 | Object | |
| 사용자 정보 | Object | |||
| 권한 정보 | Obejct | |||
| B1111 | ⇒ | Login 정보 | Object | |
| C3333 | ⇒ | … | … |
다음과 같은 구조의 세션 저장소가 생성될 수 있습니다.
세션 저장소에서는 JSESSIONID의 값마다 고유한 공간을 가지게 되는데,
이 공간은 다시 키(Key), 값(Value)으로 데이터를 보관할 수 있습니다.
예를 들어, A1234와 B1111의 경우 자신이 사용하고 있는 공간 내에 Login에 관한 정보가 존재하는데,
서버에서 프로그램을 작성할 때, 이를 이용해서 해당 사용자가 로그인 했다는 것을 인정하게 되는 방식으로 동작하게 됩니다.
경우에 따른 getSession( ) 메서드의 반환 내용은 다음과 같습니다.
JSESSIONID가 없는 경우 : 세션 저장소에 새로운 번호로 공간을 만들고, 해당 공간에 접근할 수 있는 객체를 반환 (새로운 번호는 브라우저측에 JSESSIONID 값으로 전송)
JSESSIONID가 있는 경우 : 세션 저장소에서 JSESSIONID 값을 이용해서 할당된 공간을 찾고,
이 공간에 접근할 수 있는 객체를 반환
쿠키는 서버와 브라우저 사이를 오고 가기 때문에, 보안에 취약하다는 단점을 가지고 있습니다.
이 때문에, 쿠키의 용도는 상당히 제한적이게 되는데, 예를 들어 오랜 시간 보관해야 하는 데이터는
항상 서버에 보관하고, 약각의 편의를 제공하기 위한 데이터는 쿠키로 보관하는 방식을 사용합니다.
ex) 오늘 하루 이 팝업 보지 않기, 최근 본 상품 목록 등
이와 같이 사소하고, 서버에서 보관할 필요가 딱히 없는 데이터들이 쿠키를 이용하여 처리됩니다.
쿠키의 위상이 변하게 된 가장 큰 이유는 모바일 앱에서 시작된 ‘자동 로그인’ 때문인데,
쿠키의 유효기간을 지정하는 경우에, 브라우저가 종료 되더라도 보관하는 방식으로 동작하게 되는데
, 모바일에서는 매번 사용자가 로그인하는 수고로움을 덜어줄 수 있게 됩니다.
액세스 토큰(Access Token)은 인증과 권한 부여를 위해 사용되는 보안 토큰입니다.
웹 어플리케이션에서 액세스 토큰은 사용자의 인증 상태를 확인하고, 특정한 작업이나 자원에 대한 권한을 부여하는 데 사용됩니다.
사용자는 서버로부터 Access Token과 Refresh Token을 발급받았다고 가정해보자.
(Access Token의 유효기간은 1일, Refresh Token의 유효기간은 7일)
사용자가 특정한 작업을 진행하기 위해 Access Token을 전달한다.
JWT(JSON Web Token)은 웹 애플리케이션에서 인증과 정보 교환을 위해 사용되는 컴팩트한 데이터 형식을 말하며, 짧게 요약하자면 ‘인코딩된 문자열’ 을 말합니다.
JWT는 1. 헤더(header), 2. 페이로드(payload), 3. 서명(signature) 로 구성되어 있는데,
각 부분은 ‘ . ‘ 을 이용해서 구분됩니다.
세 부분 중 페이로드에는 클레임(claim)이라고 부르는 키(Key) / 값(Value) 값으로 구성된 정보들이 저장되게 됩니다.
**io.jsonwebtoken** 라이브러리가 흔히 사용됩니다.
| 부분 | 속성 | 설명 |
|---|---|---|
| Header | typ | 토큰 타입 |
| alg | 해싱 알고리즘 | |
| Payload | iss | 토큰 발급자 |
| sub | 토큰 제목 | |
| exp | 토큰 만료시간 | |
| iat | 토큰 발급 시간 | |
| aud | 토큰 대상자 | |
| nbf | 토큰 활성 시간 | |
| jtl | JWT 고유 식별자 | |
| Signature | Header의 인코딩 + Payload의 인코딩 값을 해싱 + 비밀키 |