HTTP 통신(HTTP Request)는 기본적으로 상태가 존재하지 않는다(Stateless). 상태가 존재하지 않는다는 것은 서버로 가는 모든 요청이 이전 요청과 독립적으로 이뤄진다는 것이다. 요청끼리 연결이 되어있지 않기 때문에 요청이 끝나면 서버는 이전 요청을 다 잊고 클라이언트의 식별이 불가능하게 된다.(요청 간 사용자 데이터를 저장하는 수단을 제공하지 않는다.) 즉, 단발성이다. 따라서 서버는 요청이 어떤 브라우저에서 온 것인지 알 수 없다.
무상태의 특성 때문에 매 요청마다 클라이언트를 구분하기 위해 추가 정보를 포함할 필요가 있으며, 이 부가 정보는 서버가 해석해야 한다. 따라서 매 서버 요청마다 헤더에 쿠키를 담아 서버로 전송하거나 세션 등을 이용한다.
쿠키란 클라이언트에서 저장, 관리하는 데이터들이며 브라우저 단위로 생성되어 브라우저를 닫아도 데이터를 유지할 수 있다. 또한 도메인을 구분하기 때문에 다른 도메인을 대신하여 쿠키를 발행할 수 없다.
따라서 쿠키는 로그인 유지나 장바구니, n일 동안 보지 않기 등에 사용된다. 유저가 브라우저에 첫 방문했을 때, 로그인 요청을 서버로 보내면 서버는 해당하는 사용자를 찾아 응답 헤더 Set-Cookie
에 사용자 정보를 담아 클라이언트로 보내준다. 클라이언트는 이 쿠키를 받으면 브라우저에 쿠키를 저장한다. 이후에 사용자가 같은 브라우저를 재방문하게 되면 클라이언트는 해당 도메인에 쿠키가 있는지 확인하고, 쿠키가 있으면 그 도메인에 접속을 시도한다. 쿠키에 사용자 정보가 있기 때문에 로그인된 상태의 페이지를 보여줄 수 있다.
Set-Cookie는 Set-Cookie: 키(key)=값(value); 옵션(optioins)
으로 온다. 서버가 내려준 것을 클라이언트에서 받으면 파싱해서 사용한다. 응답 헤더에 담으면 브라우저가 알아서 저장한다.
옵션으로 설정할 수 있는 것은 다음과 같다.
Expires
: 쿠키 만료 날짜Max-Age
: 쿠키 수명(Expires
옵션보다 우선 적용)Secure
: HTTPS에서만 쿠키를 전송, HTTPS에서 설정한 쿠키는 HTTP에서 접근 불가능HttpOnly
: JavaScript에서 쿠키에 접근 못하도록 막음(document.cookie
불가능)Domain
: 도메인이 일치하는 요청만 쿠키 전송, 명시하지 않을 경우 현재 도메인을 기준으로 서브 도메인을 포함Path
: 패쓰(경로)와 일치하는 요청만 쿠키 전송, 해당되는 URL 경로와 서브 디렉토리 경로에서 쿠키에 접근 가능쿠키는 우선 4kb 용량 제한이 있다. 이 중에서는 서버에 필요하지 않은 데이터도 있기 때문에 데이터 낭비가 발생할 수 있다. 이 경우에는 서버에 필요하지 않은 데이터를 웹 스토리지를 이용해 따로 저장할 수 있다.
또한 쿠키는 XSS(Cross-Site Script) 공격에 취약하다.
XSS 공격이란, 악의적인 사용자가 악성 스크립트를 삽입하여 브라우저에서 실행하는 것이다. JavaScript를 이용해 악의적인 사용자가 다른 사용자의 쿠키값을 탈취할 수 있다. 이를 방지하기 위해 HttpOnly
속성을 제공한다. 그러나 이 속성을 사용한다 하더라도 SPA인 React의 dangerouslySetInnerHTML
같은 돔을 직접 수정하는 코드가 포함되어 있다면 탈취될 가능성이 있다.
그리고 쿠키를 암호화하지 않고 보내면 쿠키값을 중간에 탈취 당할 가능성이 있다. 이 경우에는 HTTPS를 사용하면 방지할 수 있다.
이런 쿠키의 취약점 때문에 쿠키와 세션을 함께 사용한다.
세션이란 웹 사이트에 이용되는 사용자 정보를 브라우저에 저장하는 쿠키와 달리 서버에 저장하는 방법이다.
쿠키와 세션을 함께 이용하는 방법은, 쿠키에 HTTP Session Id를 식별자로 담아 클라이언트와 서버 간 통신이 가능하게 한다. 쿠키는 자동으로 전송되므로 쿠키에 세션 Id(식별자)가 있다면 서버는 세션 Id와 함께 오는 쿠키를 통해 세션 DB에서 사용자를 알아내어 적절한 데이터로 응답할 수 있다. 클라이언트는 세션 Id를 포함한 쿠키를 브라우저에 저장한다.
여기서 쿠키는 세션 Id를 전달하기 위한 매개체가 된다. 세션을 서버에 두기 때문에 쿠키에 세션 Id 외의 정보를 기록하지 않음으로써 안전성을 확보할 수 있다.
세션은 서버에 파일로 저장되기 때문에 유저가 많아지는 경우 처리 속도와 저장 공간에 대한 비용이 생긴다는 문제점이 있다. 따라서 서버와 클라이언트간 인증은 별도 토큰을 사용하고, 쿠키는 클라이언트 자체적인 지속적인 데이터 관리 용도로 많이 사용한다.
웹 스토리지란 HTML5부터 지원하는 브라우저에 데이터를 저장할 수 있는 API이다. 4KB의 저장공간인 쿠키와 달리 최소 2MB 정도를 저장할 수 있다고 한다. window
객체에 들어있으며 Storage
객체를 상속받기 때문에 메소드가 공통적으로 존재한다.
따라서 두 스토리지 객체는 동일한 메서드와 프로퍼티를 제공한다.
setItem(key, value)
: 키(key)-값(value) 쌍 보관getItem(key)
: 키에 해당하는 값 반환removeItem(key)
: 키와 해당 값 삭제clear()
: 모든 값 삭제key(index)
: 인덱스(index)에 해당하는 키를 받아옴length
: 저장된 항목의 개수 반환자동으로 서버에 전송하지 않기 때문에 쿠키 트래픽 문제를 해결할 수 있으며 오리진(origin) 단위(프로토콜 + 호스트(도메인) + 포트)로 접근이 제한되기 때문에 프로토콜과 서브 도메인이 다르면 데이터에 접근할 수 없다.
서브 도메인은 하위 도메인으로 웹 사이트의 섹션을 구분하기 위해 도메인 이름에 추가되는 프리픽스(Prefix)이다. 서브 도메인은 해당 메인 도메인과는 별도의 웹 사이트로 작동한다.
예를 들어, 네이버의 메인 홈페이지 도메인은 "www.naver.com"이지만 네이버 블로그는 "blog.naver.com"이다. 여기서 blog가 서브 도메인이라 할 수 있다. 혹은 네이버 모바일 블로그의 도메인은 "m.blog.naver.com"으로 모바일을 나타내는 "m" 또한 네이버 블로그의 서브 도메인이라고 할 수 있다. 서브 도메인은 이처럼 모바일, 이커머스, 위치 기반, 고객센터/지원, 언어 등의 기준으로 구분하여 설정해줄 수 있다.
IndexedDB는 인덱스가 포함된 JSON 객체가 모여있는 트렌젝셔널(transactional) 로컬 데이터베이스를 위해 W3C가 새롭게 권고한 웹 브라우저 표준 인터페이스의 하나이다.
트렌젝셔널한 데이터베이스는 트랜잭션을 지원하는 데이터베이스이다. 현재 대부분의 관계형 데이터베이스 관리시스템은 트랜잭션 데이터베이스이다. 데이터베이스 트랜잭션(Database Transaction)은 데이터베이스 관리 시스템(DBMS)에서 상호작용의 단위이다. 데이터베이스 시스템은 각각의 트랜잭션에 대해 원자성(Atomicity), 일관성(Consistency), 독립성(Isolation), 영구성(Durability)을 보장해야 한다. 즉, 모든 쿼리가 성공할 때만 성공으로 하는 성공과 실패가 명확하여야 하며, 트렌젝션끼리는 서로 간섭하지 않아야 한다.
또한 자바스크립트 기반의 객체지향 데이터베이스 시스템이다. 각 객체는 삽입 중에 생성되는 키로 식별하고 키(key)-값(value)으로 데이터를 관리하며 문자열만 저장할 수 있는 로컬스토리지와는 달리, 자바스크립트가 인식할 수 있는 자료형과 객체를 저장할 수 있다.
IndexedDB 데이터는 영구적으로 유지되지만 시크릿 모드에서 사용하면 값은 저장되지 않고 브라우저가 종료되면 사라진다. 저장 조건은 오리진(origin) 단위(프로토콜 + 호스트(도메인) + 포트)이다.
웹 스토리지의 경우 동기적으로 실행되어 적은 양의 데이터를 저장하는데 유용하다. 그러나 IndexedDB는 비동기적으로 작동하며 많은 양의 구조화된 데이터를 저장하는데 유용하다.