JavaScript — Работа с cookies

Cookies — это технология, позволяющая сайтам сохранять в браузере небольшую порцию данных (до 4Кбайт).
Обычно эти данные используются на сайте для того, чтобы:
- «узнать» (идентифицировать) пользователя (эмулировать постоянное соединение с сервером);
- сохранить информацию о просмотренных страницах или товаров;
- осуществить простую защиту счётчиков и системы голосования от накрутки;
- запомнить настройки интерфейса, расположение блоков, товара, добавленного в корзину и много другого.
Как работают cookies
Механизм работы с cookies рассмотрим на следующем примере:
- Клиент (веб-браузер) посылает серверу запрос (запрашивает у него страницу). Если в браузере есть cookies, связанные с этим сайтом, то он их посылает серверу в составе этого запроса.
- Сервер получает запрос от клиента. Если в составе запроса есть куки, то их можно использовать для выполнения некоторой логики на сервере, подготовки пользователю персонализированной страницы или для чего-то другого. После этого отправляем клиенту ответ. В заголовке ответа отправляем веб-браузеру (клиенту) cookies, которые ему нужно будет сохранить.
- Веб-браузер (клиент) получает ответ от сервера (страницу) и выводит его пользователю. Куки, которые пришли с сервера, браузер сохраняет в своё хранилище.
JavaScript — document.cookie
Но прочитать и установить cookies можно не только на стороне сервера, но и на клиенте — с помощью JavaScript. Осуществляется это посредством свойства cookie объекта document .
Данное свойство представляет собой строку и чтобы в ней что-то найти, например, определённую cookie (по ключу), её необходимо разобрать. Для этого нужно написать JavaScript код (например, с использованием регулярных выражений) или воспользоваться специально предназначенного для этого библиотекой js-cookie. Данная библиотека, кроме функции чтения куки, имеет также методы для её установки и удаления.
Библиотека js-cookie
js-cookie — библиотека JavaScript, предоставляющая методы для удобной работы с cookies.
Подключение js-cookie к странице Установка (set) cookie Запись cookie осуществляется с помощью функции set : Установить cookie для всех страниц сайта: Создать cookie, действительную 30 дней (от текущего момента времени) и видимую любыми страницами сайта: Выполнить запись куки, доступ к которой будет иметь только текущая страница (срок хранения 365 дней): Получение (get) куки Чтение значения cookie осуществляется с помощью метода get : Получить все доступные cookies: Удаление (remove) cookie Для удаления куки предназначена функция remove : Удаление cookie с указанием атрибута path :
Важно! Когда вы удаляете cookie, вы должны указать тот же самый путь и домен, который использовался для установки cookie. Если атрибуты куки в Cookies.remove не указать, то будут браться те, которые заданы по умолчанию в Cookies.defaults (приведён ниже).
-
expires — указывает длительность хранения cookie в браузере. Значение можно задавать как в формате числа (количество дней от текущего момента времени), так и ввиде даты. Если данный параметр не указать, то cookie будет ссесионным, т.е. он удалится после закрытия браузера.
Например, установим cookie на 30 дней (в качестве формата expires будем использовать дату):
Cookie, которая будет иметь в качестве пути текущее местоположение документа:
Как сохранить объект в куках js
БлогNot. Как сохранить массив или объект в cookies
Как сохранить массив или объект в cookies
В этой статье для сохранения нескольких «ключиков» cookies мы применяли отдельные скалярные переменные. Не сложнее будет сохранить и составное значение, такое как массив или объект. Мы должны будем сцепить массив или объект в строку перед сохранением, а потом после чтения расцепить обратно, при необходимости также клонируя прочитанные данные в массив или объект внутри нашего скрипта.
Вот пример, который можно сохранить и выполнить как файл .html в кодировке Юникода utf-8, помня, что не все браузеры разрешают работать с cookies локальным файлам, открытым через файловую систему, а не по протоколу HTTP (см. в статье по ссылке выше).
Сохранение делается по нажатию кнопки, а восстановление — при начальной загрузке страницы, если данные были ранее сохранены. Поэтому для проверки скрипта достаточно нажать кнопку «Сохранить», а затем «Перезагрузить».
В консоли браузера мы можем увидеть, что куки действительно создано всего две. Также пример показывает некоторые тонкости обращения с составными объектами — как «физически», а не по ссылке скопировать массив ( arr.slice(0) ) и объект ( Object.assign(obj) ), как преобразовать массив и объект в строку ( arr.join(separator) , JSON.stringify(obj) ) и обратно ( string.split(separator) , JSON.parse(string) ).
Cookies примера в консоли браузера Firefox (Ctrl+Shift+K)
How can I store JavaScript objects in cookies?
This tutorial will teach us to store JavaScript objects into the cookies. The cookies are the information of website visitors stored in the text files. There is a particular mechanism to store the cookies of users’ browsers. When new visitors visit the website, the server generates the text and sends it to the user. After that, when users allow access to the web page to retrieve the cookies, the server stores all user information in the text files.
Cookies store the user’s search history or other information for a better experience. For example, Google stores the user’s search history to server ads on the web pages according to the user’s interest. YouTube stores cookies to recommend videos with the user’s interest.
Here, we will learn the basic method to store and get cookies to the web server.
Set cookies for the particular web page
First, we will learn to set cookies and get cookies from the browser. We will store the basic information in the form of a string. Also, we set the expiry of the cookies. Users can also add the path to the cookies to know to which location, the cookies have been set up.
Users can follow the below syntax to store cookies and get cookies from the browser.
Syntax
Algorithm (Get a Particular Cookie)
When we store some information to the cookie values, it appends to the previous cookies and doesn’t override the old values. So, when we use the document.cookies, it returns all the stored cookies. We need to fetch the required cookies from all key-values pairs of the cookies.
Here is the algorithm to create a function to fetch the required key value from the cookie.
Step 1 − Get the row cookies string format using the document.cookie method.
Step 2 − Split the cookies by the semi-colon(;), and it will return the array of the key-value pairs.
Step 3 − Iterate through the one-by-one key-value pair to find the required key.
Step 4 − While iterating through the key-value pair, remove the space from the front of the key and check that the key matches with our required key or not.
Step 5 − If a key is found, return the value for that key. Otherwise, that key-value pair is not stored in the cookies.
Example
In the below example, we have stored the cookies in the browser using the document.cookie. We have implemented the above algorithm to find the key-value pair from the cookies.
We have used the window.onload() method to store the cookies when the web page loads.
In the below output, users can see that we have retrieved the user id and info from the cookies.
Store objects in the Cookies
Now, we have learned how cookies work in JavaScript and how we can store it on the server. The cookies store information in the string format only. If users want to store any other types of data in the cookies, they need to convert it to the string using the stringify() method.
In this section, we will convert the object to a string and store it in cookies. Also, we will retrieve the object from the cookies.
Syntax
Follow the below syntax to store the object in the cookies.
Example
In the below example, we have stored the object into the cookies after converting it into the string using the JSON.stringify() method. We have used the same algorithm used in the previous section to retrieve the object from the cookies.
Well, we have looked at how cookies work in JavaScript. The cookies send user information to the server. So, maybe hackers can attack and get the user information. Also, cookie stores around 4kb of data in the text files.
Nowadays, every modern browser supports session storage, storing the data in the local computer. The webpage can retrieve the data from the session storage or local store when required rather than fetching the data from the cookies. So, it is recommended to use the session storage rather than cookies as it is more secure, and users can store up to 10MB of data.
Куки, document.cookie
Куки – это небольшие строки данных, которые хранятся непосредственно в браузере. Они являются частью HTTP-протокола, определённого в спецификации RFC 6265.
Куки обычно устанавливаются веб-сервером при помощи заголовка Set-Cookie . Затем браузер будет автоматически добавлять их в (почти) каждый запрос на тот же домен при помощи заголовка Cookie .
Один из наиболее частых случаев использования куки – это аутентификация:
- При входе на сайт сервер отсылает в ответ HTTP-заголовок Set-Cookie для того, чтобы установить куки со специальным уникальным идентификатором сессии («session identifier»).
- Во время следующего запроса к этому же домену браузер посылает на сервер HTTP-заголовок Cookie .
- Таким образом, сервер понимает, кто сделал запрос.
Мы также можем получить доступ к куки непосредственно из браузера, используя свойство document.cookie .
Куки имеют множество особенностей и тонкостей в использовании, и в этой главе мы подробно с ними разберёмся.
Чтение из document.cookie
Хранит ли ваш браузер какие-то куки с этого сайта? Посмотрим:
Значение document.cookie состоит из пар ключ=значение , разделённых ; . Каждая пара представляет собой отдельное куки.
Чтобы найти определённое куки, достаточно разбить строку из document.cookie по ; , и затем найти нужный ключ. Для этого мы можем использовать как регулярные выражения, так и функции для обработки массивов.
Оставим эту задачу читателю для самостоятельного выполнения. Кроме того, в конце этой главы вы найдёте полезные функции для работы с куки.
Запись в document.cookie
Мы можем писать в document.cookie . Но это не просто свойство данных, а акcессор (геттер/сеттер). Присваивание к нему обрабатывается особым образом.
Запись в document.cookie обновит только упомянутые в ней куки, но при этом не затронет все остальные.
Например, этот вызов установит куки с именем user и значением John :
Если вы запустите этот код, то, скорее всего, увидите множество куки. Это происходит, потому что операция document.cookie= перезапишет не все куки, а лишь куки с вышеупомянутым именем user .
Технически, и имя и значение куки могут состоять из любых символов, для правильного форматирования следует использовать встроенную функцию encodeURIComponent :
Существует несколько ограничений:
- После encodeURIComponent пара name=value не должна занимать более 4Кб. Таким образом, мы не можем хранить в куки большие данные.
- Общее количество куки на один домен ограничивается примерно 20+. Точное ограничение зависит от конкретного браузера.
У куки есть ряд настроек, многие из которых важны и должны быть установлены.
Эти настройки указываются после пары ключ=значение и отделены друг от друга разделителем ; , вот так:
- path=/mypath
URL-префикс пути, куки будут доступны для страниц под этим путём. Должен быть абсолютным. По умолчанию используется текущий путь.
Если куки установлено с path=/admin , то оно будет доступно на страницах /admin и /admin/something , но не на страницах /home или /adminpage .
Как правило, указывают в качестве пути корень path=/ , чтобы наше куки было доступно на всех страницах сайта.
domain
- domain=site.com
Домен определяет, где доступен файл куки. Однако на практике существуют определённые ограничения. Мы не можем указать здесь какой угодно домен.
Нет никакого способа разрешить доступ к файлам куки из другого домена 2-го уровня, поэтому other.com никогда не получит куки, установленный по адресу site.com .
Это ограничение безопасности, позволяющее нам хранить конфиденциальные данные в файлах куки, которые должны быть доступны только на одном сайте.
По умолчанию куки доступны лишь тому домену, который его установил.
Пожалуйста, обратите внимание, что по умолчанию файл куки также не передаётся поддомену, например forum.site.com .
…Но это можно изменить. Если мы хотим разрешить поддоменам типа forum.site.com получать куки, установленные на site.com , это возможно.
Чтобы это произошло, при установке файла куки в site.com , мы должны явно установить параметр domain для корневого домена: domain=site.com . После этого все поддомены увидят такой файл cookie.
По историческим причинам установка domain=.site.com (с точкой перед site.com ) также работает и разрешает доступ к куки для поддоменов. Это старая запись, но можно использовать и её, если нужно, чтобы поддерживались очень старые браузеры.
Таким образом, опция domain позволяет нам разрешить доступ к куки для поддоменов.
expires, max-age
По умолчанию, если куки не имеют ни одного из этих параметров, то они удалятся при закрытии браузера. Такие куки называются сессионными («session cookies»).
Чтобы помочь куки «пережить» закрытие браузера, мы можем установить значение опций expires или max-age .
- expires=Tue, 19 Jan 2038 03:14:07 GMT
Дата истечения срока действия куки, когда браузер удалит его автоматически.
Дата должна быть точно в этом формате, во временной зоне GMT. Мы можем использовать date.toUTCString , чтобы получить правильную дату. Например, мы можем установить срок действия куки на 1 день.
Если мы установим в expires прошедшую дату, то куки будет удалено.
- max-age=3600
Альтернатива expires , определяет срок действия куки в секундах с текущего момента.
Если задан ноль или отрицательное значение, то куки будет удалено:
secure
- secure
Куки следует передавать только по HTTPS-протоколу.
По умолчанию куки, установленные сайтом http://site.com , также будут доступны на сайте https://site.com и наоборот.
То есть, куки, по умолчанию, опираются на доменное имя, они не обращают внимания на протоколы.
С этой настройкой, если куки будет установлено на сайте https://site.com , то оно не будет доступно на том же сайте с протоколом HTTP, как http://site.com . Таким образом, если в куки хранится конфиденциальная информация, которую не следует передавать по незашифрованному протоколу HTTP, то нужно установить этот флаг.
samesite
Это ещё одна настройка безопасности, применяется для защиты от так называемой XSRF-атаки (межсайтовая подделка запроса).
Чтобы понять, как настройка работает и где может быть полезной, посмотрим на XSRF-атаки.
Атака XSRF
Представьте, вы авторизовались на сайте bank.com . То есть: у вас есть куки для аутентификации с этого сайта. Ваш браузер отправляет его на сайт bank.com с каждым запросом, чтобы сервер этого сайта узнавал вас и выполнял все конфиденциальные финансовые операции.
Теперь, просматривая веб-страницу в другом окне, вы случайно переходите на сайт evil.com , который автоматически отправляет форму <form action="https://bank.com/pay"> на сайт bank.com с заполненными полями, которые инициируют транзакцию на счёт хакера.
Браузер посылает куки при каждом посещении bank.com , даже если форма была отправлена с evil.com . Таким образом, банк узнает вас и выполнит платёж.
Такая атака называется межсайтовая подделка запроса (или Cross-Site Request Forgery, XSRF).
Конечно же, в реальной жизни банки защищены от такой атаки. Во всех сгенерированных сайтом bank.com формах есть специальное поле, так называемый «токен защиты от xsrf», который вредоносная страница не может ни сгенерировать, ни каким-либо образом извлечь из удалённой страницы (она может отправить форму туда, но не может получить данные обратно). И сайт bank.com при получении формы проверяет его наличие.
Но такая защита требует усилий на её реализацию: нам нужно убедиться, что в каждой форме есть поле с токеном, также мы должны проверить все запросы.
Настройка samesite
Параметр куки samesite предоставляет ещё один способ защиты от таких атак, который (теоретически) не должен требовать «токенов защиты xsrf».
У него есть два возможных значения:
- samesite=strict (или, что то же самое, samesite без значения)
Куки с samesite=strict никогда не отправятся, если пользователь пришёл не с этого же сайта.
Другими словами, если пользователь переходит по ссылке из почты, отправляет форму с evil.com или выполняет любую другую операцию, происходящую с другого домена, то куки не отправляется.
Если куки имеют настройку samesite , то атака XSRF не имеет шансов на успех, потому что отправка с сайта evil.com происходит без куки. Таким образом, сайт bank.com не распознает пользователя и не произведёт платёж.
Защита довольно надёжная. Куки с настройкой samesite будет отправлено только в том случае, если операции происходят с сайта bank.com , например отправка формы сделана со страницы на bank.com .
Хотя есть небольшие неудобства.
Когда пользователь перейдёт по ссылке на bank.com , например из своих заметок, он будет удивлён, что сайт bank.com не узнал его. Действительно, куки с samesite=strict в этом случае не отправляется.
Мы могли бы обойти это ограничение, используя два куки: одно куки для «общего узнавания», только для того, чтобы поздороваться: «Привет, Джон», и другое куки для операций изменения данных с samesite=strict . Тогда пользователь, пришедший на сайт, увидит приветствие, но платежи нужно инициировать с сайта банка, чтобы отправилось второе куки.
- samesite=lax
Это более мягкий вариант, который также защищает от XSRF и при этом не портит впечатление от использования сайта.
Режим Lax так же, как и strict , запрещает браузеру отправлять куки, когда запрос происходит не с сайта, но добавляет одно исключение.
Куки с samesite=lax отправляется, если два этих условия верны:
Используются безопасные HTTP-методы (например, GET, но не POST).
Полный список безопасных HTTP-методов можно посмотреть в спецификации RFC7231. По сути, безопасными считаются методы, которые обычно используются для чтения, но не для записи данных. Они не должны выполнять никаких операций на изменение данных. Переход по ссылке является всегда GET-методом, то есть безопасным.
Операция осуществляет навигацию верхнего уровня (изменяет URL в адресной строке браузера).
Обычно это так, но если навигация выполняется в <iframe> , то это не верхний уровень. Кроме того, JavaScript-методы для сетевых запросов не выполняют никакой навигации, поэтому они не подходят.
Таким образом, режим samesite=lax , позволяет самой распространённой операции «переход по ссылке» передавать куки. Например, открытие сайта из заметок удовлетворяет этим условиям.
Но что-то более сложное, например, сетевой запрос с другого сайта или отправка формы, теряет куки.
Если это вам подходит, то добавление samesite=lax , скорее всего, не испортит впечатление пользователей от работы с сайтом и добавит защиту.
В целом, samesite отличная настройка.
Но у неё есть важный недостаток:
- samesite игнорируется (не поддерживается) старыми браузерами, выпущенными до 2017 года и ранее.
Так что, если мы будем полагаться исключительно на samesite , то старые браузеры будут уязвимы.
Но мы, безусловно, можем использовать samesite вместе с другими методами защиты, такими как XSRF-токены, чтобы добавить дополнительный слой защиты, а затем, в будущем, когда старые браузеры полностью исчезнут, мы, вероятно, сможем полностью удалить XSRF-токены.
httpOnly
Эта настройка не имеет ничего общего с JavaScript, но мы должны упомянуть её для полноты изложения.
Веб-сервер использует заголовок Set-Cookie для установки куки. И он может установить настройку httpOnly .
Эта настройка запрещает любой доступ к куки из JavaScript. Мы не можем видеть такое куки или манипулировать им с помощью document.cookie .
Эта настройка используется в качестве меры предосторожности от определённых атак, когда хакер внедряет свой собственный JavaScript-код в страницу и ждёт, когда пользователь посетит её. Это вообще не должно быть возможным, хакер не должен быть в состоянии внедрить свой код на ваш сайт, но могут быть ошибки, которые позволят хакеру сделать это.
Обычно, если такое происходит, и пользователь заходит на страницу с JavaScript-кодом хакера, то этот код выполняется и получает доступ к document.cookie , и тем самым к куки пользователя, которые содержат аутентификационную информацию. Это плохо.
Но если куки имеет настройку httpOnly , то document.cookie не видит его, поэтому такое куки защищено.
Приложение: Функции для работы с куки
Вот небольшой набор функций для работы с куки, более удобных, чем ручная модификация document.cookie .
Для этого существует множество библиотек, так что они, скорее, в демонстрационных целях. Но при этом полностью рабочие.
getCookie(name)
Самый короткий способ получить доступ к куки – это использовать регулярные выражения.
Функция getCookie(name) возвращает куки с указанным name :
Здесь new RegExp генерируется динамически, чтобы находить ; name=<value> .
Обратите внимание, значение куки кодируется, поэтому getCookie использует встроенную функцию decodeURIComponent для декодирования.
setCookie(name, value, options)
Устанавливает куки с именем name и значением value , с настройкой path=/ по умолчанию (можно изменить, чтобы добавить другие значения по умолчанию):
deleteCookie(name)
Чтобы удалить куки, мы можем установить отрицательную дату истечения срока действия:
Обратите внимание: когда мы обновляем или удаляем куки, нам следует использовать только такие же настройки пути и домена, как при установке куки.
Приложение: Сторонние куки
Куки называются сторонними, если они размещены с домена, отличающегося от страницы, которую посещает пользователь.
Страница site.com загружает баннер с другого сайта: <img src="https://ads.com/banner.png"> .
Вместе с баннером удалённый сервер ads.com может установить заголовок Set-Cookie с куки, например, id=1234 . Такие куки создаются с домена ads.com и будут видны только на сайте ads.com :
В следующий раз при доступе к ads.com удалённый сервер получит куки id и распознает пользователя:
Что ещё более важно, когда пользователь переходит с site.com на другой сайт other.com , на котором тоже есть баннер, то ads.com получит куки, так как они принадлежат ads.com , таким образом ads.com распознает пользователя и может отслеживать его перемещения между сайтами:
Сторонние куки в силу своей специфики обычно используются для целей отслеживания посещаемых пользователем страниц и показа рекламы. Они привязаны к исходному домену, поэтому ads.com может отслеживать одного и того же пользователя на разных сайтах, если оттуда идёт обращение к нему.
Естественно, некоторым пользователям не нравится, когда их отслеживают, поэтому браузеры позволяют отключать такие куки.
Кроме того, некоторые современные браузеры используют специальные политики для таких куки:
- Safari вообще не разрешает сторонние куки.
- У Firefox есть «чёрный список» сторонних доменов, чьи сторонние куки он блокирует.
Если мы загружаем скрипт со стороннего домена, например <script src="https://google-analytics.com/analytics.js"> , и этот скрипт использует document.cookie , чтобы установить куки, то такое куки не является сторонним.
Если скрипт устанавливает куки, то нет разницы откуда был загружен скрипт – куки принадлежит домену текущей веб-страницы.
Приложение: GDPR
Эта тема вообще не связана с JavaScript, но следует её иметь в виду при установке куки.
В Европе существует законодательство под названием GDPR, которое устанавливает для сайтов ряд правил, обеспечивающих конфиденциальность пользователей. И одним из таких правил является требование явного разрешения от пользователя на использование отслеживающих куки.
Обратите внимание, это относится только к куки, используемым для отслеживания/идентификации/авторизации.
То есть, если мы установим куки, которые просто сохраняют некоторую информацию, но не отслеживают и не идентифицируют пользователя, то мы свободны от этого правила.
Но если мы собираемся установить куки с информацией об аутентификации или с идентификатором отслеживания, то пользователь должен явно разрешить это.
Есть два основных варианта как сайты следуют GDPR. Вы наверняка уже видели их в сети:
Если сайт хочет установить куки для отслеживания только для авторизованных пользователей.
То в регистрационной форме должен быть установлен флажок «принять политику конфиденциальности» (которая определяет, как используются куки), пользователь должен установить его, и только тогда сайт сможет использовать авторизационные куки.
Если сайт хочет установить куки для отслеживания всем пользователям.
Чтобы сделать это законно, сайт показывает модальное окно для пользователей, которые зашли в первый раз, и требует от них согласие на использование куки. Затем сайт может установить такие куки и показать пользователю содержимое страницы. Хотя это создаёт неудобства для новых посетителей – никому не нравится наблюдать модальные окна вместо контента. Но GDPR в данной ситуации требует явного согласия пользователя.
GDPR касается не только куки, но и других вопросов, связанных с конфиденциальностью, которые выходят за рамки материала этой главы.