본문 바로가기

Develop/Frontend 가이드

[FE] Web API - Client-side storage : 쿠키 Cookie

반응형

Client-side Storage
Client-side Storage

Web API - Client-side storage

브라우저 환경에서 데이터를 저장하는 방법을 시리즈 글로 소개하고 있습니다.

쿠키 Cookie

Cookie
https://www.stockio.com/free-icon/bakery-icons-cookie

과거부터 지금까지 사랑받고 있는 방법은 쿠키 Cookie 입니다. 원래 HTTP 프로토콜은 Stateless 한 프로토콜로 과거 통신 상태를 기록하지 않는 프로토콜입니다. 따라서 순수한 HTTP 통신만으로는 클라이언트를 구분하여 반응하거나 클라이언트 상태에 따라 대응할 수 없습니다. 즉 어떤 클라이언트이던지 동일한 요청에 동일한 응답을 합니다. 하지만 현실적으로 클라이언트로부터 오는 요청을 상태에 따라 다르게 처리할 방법이 필요했습니다. 예를 들어, 서버가 클라이언트로 받는 요청이 로그인한 사용자가 보낸 요청인지 아닌지를 판별하거나, 동일한 클라이언트로부터 오는 요청인지 판별하거나, 클라이언트 테마 별로 다른 데이터를 전송하는 등의 작업을 하기 위해선 클라이언트의 상태를 기록하고 유지할 방법이 필요했고 그 방법이 쿠키 Cookie 인 것입니다.

맨 처음 쿠키는 클라이언트의 HTTP 요청에 대한 서버의 응답으로 만들어집니다. 서버는 HTTP 응답 헤더에 Set-Cookie 를 만들어서 초기 쿠키 값을 클라이언트에게 전달합니다. 클라이언트인 브라우저는 서버로부터 전달받은 쿠키를 운영체제 파일시스템 특정 경로에 파일로 저장합니다. 정확하게는 Windows 10 운영체제의 Chrome 브라우저는 C:\Users\사용자 이름\AppData\Local\Google\Chrome\User Data\Default\Cookies 에 쿠키를 저장합니다. 그리고 클라이언트는 서버에게 보내는 모든 HTTP 요청에 Cookie 헤더를 첨부하여 전송하고, 서버는 클라이언트로 받은 쿠키를 바탕으로 어느 클라이언트에게서 온 요청인지를 판별합니다.

클라이언트는 서버에게 보내는 모든 요청에 쿠키 정보를 담아 보내기 때문에 쿠키가 커지면 성능을 저하시킬 수 있습니다. 따라서 매 요청마다 서버에 반드시 보내야 하는 데이터가 아니라면 localStorage 나 sessionStorage 를 사용해야 합니다.

쿠키와 관련하여 요청과 응답의 헤더가 어떻게 설정되는지 아래에 예제를 제시하였습니다.

맨 처음 서버에서 보내는 쿠키는 다음과 같은 형태로 보냅니다.

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]

클라이언트는 서버로부터 받은 응답에서 Set-Cookie 에 있는 데이터를 자신의 쿠키로 저장한 뒤, 서버에 전송할 모든 요청에 다음과 같은 형태로 쿠키를 담아 전달합니다.

GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

신기하게도 서버에서 보내는 Set-Cookie 헤더는 데이터마다 헤더를 나눠서 보내는 반면에, 클라이언트에서 보내는 쿠키는 한 줄에 모든 데이터를 담아 보냅니다. Set-Cookie 헤더와 Cookie 헤더의 형태가 다른 이유는 쿠키에 대한 설정을 서버에서 하는데 각 쿠키마다 설정하는 값이 다를 수 있기 때문에 쿠키마다 Set-Cookie 로 나눠서 정의합니다.

서버가 할 수 있는 쿠키 설정 중 제일 중요한 설정은 쿠키의 수명을 결정하는 설정입니다. 쿠키는 수명에 따라 크게 두 타입으로 나뉩니다. 한 타입은 세션 쿠키 Session Cookie 로 세션의 수명과 동일한 수명을 가지는 쿠키입니다. 따라서 세션이 종료되면 쿠키는 소멸하게 됩니다. 대체로 브라우저의 탭을 종료하면 세션을 종료하게 되며 이때 세션 쿠키도 소멸하게 됩니다. 하지만 많은 브라우저가 탭이 닫혔을 때 세션 쿠키를 제거했다가, 브라우저가 종료되지 않은 채로 동일한 탭을 다시 열면 세션 쿠키를 복구하고 있습니다. 따라서 세션 쿠키가 정말 삭제되어 접근이 불가능해지려면 브라우저를 종료해야 할 수도 있습니다. 쿠키의 수명을 설정하지 않으면 기본적으로 세션 쿠키가 됩니다. 나머지 타입은 영구 쿠키 Permanent cookie 로 쿠키 설정 중 Expires 나 Max-Age 를 설정하면 영구 쿠키가 됩니다. 만약 Expires 와 Max-age 모두 설정할 경우 Max-age 가 쿠키의 수명이 됩니다. 쿠키의 수명은 다음과 같이 설정하면 됩니다.

Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;

Expires 는 쿠키의 수명을 특정한 날짜로 설정하는데, 날짜를 비교하는 기준이 서버가 아닌 클라이언트의 날짜를 바탕으로 판단합니다. 따라서 쿠키의 수명이 클라이언트의 시간에 따라 달라지기 때문에 쿠키의 정확한 수명을 예측할 수 없습니다. 예를 들어, 쿠키의 수명이 23 시간 이하일 경우 서버와 클라이언트가 지구 어디에 위치하느냐에 따라 쿠키가 바로 만료되어 버릴 수 있습니다. 따라서 Max-Age 를 설정하는게 더욱 안전합니다. 하지만! 악동 IE 는 Max-Age 를 지원하지 않기 때문에... 더이상 말하지 않겠습니다.

쿠키에 중요한 정보가 담겨 있을 수 있기 때문에 쿠키에도 보안을 설정할 수 있습니다. 쿠키 설정 중 Secure 를 설정하면 localhost 도메인을 제외하고는 HTTPS 프로토콜으로만 전송할 수 있습니다.

쿠키 보안 설정 중 HttpOnly 를 설정하면, JavaScript 로 쿠키를 접근할 수 없게 됩니다. 원래 쿠키는 아래와 같이 JavaScript Document.cookie 코드로 접근할 수 있습니다.

// 새로운 쿠키를 설정합니다.
document.cookie = "test1=Hello; expires=Fri, 31 Dec 9999 23:59:59 GMT";
// 기존 쿠키에 접근합니다.
document.cookie.split('; ').find(row => row.startsWith('test1'));

하지만 쿠키에 아래와 같이 HttpOnly 를 적용하면 위와 같이 JavaScript 코드로 쿠키에 접근할 수 없게 됩니다.

Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly

쿠키의 보안과 관련하여 더 자세한 내용은 이 글이 글 을 참고해주시길 바랍니다.

2018년 5월 25일을 기점으로 EU 가 제정한 일반개인정보보호법 (GDPR General Data Protection Regulation) 이 효력을 발휘하게 되면서 쿠키를 용도에 따라 구별하여 동의를 얻는 사이트가 급증하게 되었습니다. 쿠키를 구별하는 기준이 명확하지는 않지만 대체로 필수적으로 사용해야 하는 쿠키와 기능을 향상시키거나 추가하는 쿠키, 그리고 사용자를 분석하는 활용되는 쿠키와 광고에 활용되는 쿠키로 구분하여 동의를 받고 있습니다.

Session 세션

Session 세션 은 서버와 클라이언트 간에 개념적으로 연결을 유지하는 기간을 의미합니다. 대체로 30분 이상 클라이언트로부터 요청이 없으면 서버는 클라이언트와 연결이 끊어졌다고 판단하고 해당 세션과 관련된 데이터를 해제합니다. 실제 네트워크 상에 서버와 클라이언트의 연결은 HTTP 프로토콜의 TCP 연결로 이루어지지만, HTTP/1.1 에서는 TCP 의 연결과 해제가 빈번하여 클라이언트와 서버의 연결 상태를 판단하는데 사용하기에는 문제가 있습니다. 그래서 만든 것이 Session 세션 이라는 개념입니다.

세션은 쿠키에 기반하여 만들어진 개념입니다. 클라이언트는 모든 요청에 쿠키를 포함하여 전송하기 때문에 쿠키에 사용자 정보를 담아 전달하는 건 보안상 그리고 성능상 문제가 됩니다. 따라서 민감한 데이터는 서버 내부적으로 처리될 수 있도록 해야 합니다. 이때 사용하는게 '세션 키' 입니다. 서버는 먼저 쿠키에 각 클라이언트의 세션을 구분할 수 있는 키를 설정하여 클라이언트에게 전달합니다. 일반적으로 JSESSIONID 라는 쿠키에 세션를 구별하는 키 값이 담겨 전달됩니다. 그리고 세션 키를 받은 클라이언트가 로그인하면서 세션 키를 쿠키에 담아 서버로 전달하면, 서버는 클라이언트에게 전달했던 세션 키과 동일한 세션 키인지 확인한 뒤에, 사용자와 연결된 새로운 세션 키를 발급하고 새로운 세션 키와 사용자 정보를 연결하여 관리합니다. 따라서 서버는 사용자 정보와 같이 민감한 정보를 클라이언트에게 쿠키로 전달하지 않고 이제 세션 키로 사용자를 구분할 수 있게 됩니다.

세션의 수명은 서버가 별도로 설정하지 않으면 대체로 30 분입니다. 서버가 클라이언트의 로그인 요청에 응답을 보낸 뒤, 30분 이상 클라이언트로부터 다른 요청을 받지 못하면 서버 내에 로그인했던 기록을 해제합니다. 즉 발급했던 세션 키를 삭제합니다. 로그인 정보와 연결된 세션 키가 서버에서 삭제되어 버렸으므로, 클라이언트는 다시 로그인 시도해야 합니다. 하지만 만약 30분 내에 클라이언트가 서버로 요청을 보냈다면 타이머는 다시 30 분으로 초기화됩니다.

세션 쿠키는 로그인한 클라이언트를 대변하는 성격을 띄기 때문에 세션 쿠키가 유출되지 않도록 보안에 신경을 써야 합니다. 대체로 위에 설명한 쿠키 보안 설정인 Secure 와 HttpOnly 를 설정하는게 일반적이며 서버를 구현하는 프레임워크 단에서 기본으로 설정되어 있지만 제대로 설정되어 있는지 검토할 필요는 있습니다.

반응형