HTTP cookie

07.10.2018

Теги: CookieHTTPHTTPSJavaScriptlocalStoragePHPphp.inisessionStorageWeb-разработка

HTTP cookie — это небольшой фрагмент данных, отправляемый сервером браузеру пользователя, который тот должен сохранить и отсылать обратно с каждым новым запросом этому серверу. Это, в частности, позволяет узнать, с одного ли браузера пришли оба запроса (например, для аутентификации пользователя). Они запоминают информацию о состоянии для протокола HTTP, который сам по себе этого делать не умеет.

Cookie используются, главным образом, для:

  • Управления сеансом (логины, корзины для интернет-магазинов)
  • Персонализации (пользовательские предпочтения)
  • Мониторинга (отслеживания поведения пользователя)

Кроме того, до недавнего времени было принято использовать cookie в качестве хранилища информации на стороне пользователя. Но из-за того, что cookie пересылаются с каждым запросом, они могут сильно снижать производительность (особенно в мобильных устройствах). Теперь качестве хранилищ данных на стороне пользователя вместо них можно использовать localStorage, sessionStorage и IndexedDB.

Создание cookie

Получив HTTP-запрос, вместе с ответом сервер может отправить заголовок Set-Cookie. Cookie запоминаются браузером и посылаются серверу с каждым новым запросом. Можно задать срок действия cookie, то есть срок его жизни, после которого cookie не будет отправляться. Также можно указать ограничения на путь и домен, то есть указать, где cookie будет действовать — по какому пути и на каком домене. Например, cookie будут действительны для пути www.server.com/private или для домена private.server.com.

Заголовки Set-Cookie и Cookie

Заголовок Set-Cookie используется для отправки cookie с сервера на клиентское приложение (браузер). Этот заголовок с сервера дает клиенту указание сохранить cookie.

Set-Cookie: <имя-cookie>=<значение-cookie>
HTTP/1.1 200 OK
Date: Sun, 07 Oct 2018 13:31:17 GMT
Server: Apache/2.4.34 (Win64) mod_fcgid/2.3.9
X-Powered-By: PHP/7.1.10
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; path=/
Set-Cookie: visitor=0d3749f09d222bea3b8f163937eb9bf1; Max-Age=31536000; path=/
Set-Cookie: lastvisit=1538919655; path=/
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
..........

Теперь, с каждым новым запросом к серверу, при помощи заголовка Cookie браузер будет возвращать серверу все сохраненные ранее cookies:

GET /catalog HTTP/1.1
Host: www.server.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.server.com/
Cookie: PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; visitor=0d3749f09d222bea3b8f163937eb9bf1; lastvisit=1538919655
Connection: keep-alive
Upgrade-Insecure-Requests: 1

Сессионные, постоянные и безопасные cookie

Сессионные cookie, установка которых выглядит так:

Set-Cookie: lastvisit=1538919655

удаляются при закрытии окна браузера, то есть существуют только на протяжении текущего сеанса, поскольку атрибуты Expires или Max-Age для них не задаются.

Постоянные cookie удаляются не с закрытием клиента, а при наступлении определенной даты (атрибут Expires) или после определенного интервала времени (атрибут Max-Age):

Set-Cookie: visitor=0d3749f09d222bea3b8f163937eb9bf1; Max-Age=31536000
Set-Cookie: visitor=0d3749f09d222bea3b8f163937eb9bf1; expires=Mon, 07-Oct-2019 13:44:02 GMT

Безопасные cookie отсылаются на сервер только если запрос выполняется по протоколу SSL и HTTPS. Начиная с Chrome 52 и Firefox 52, незащищенные сайты (HTTP) не могут создавать куки с флагом secure.

Set-Cookie: PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; Secure

HttpOnly cookie не доступны из JavaScript через свойство document.cookie и через XMLHttpRequest, что помогает избежать межсайтового скриптинга (XSS). Рекомендуется устанавливать этот флаг для тех cookie, к которым не требуется обращаться через JavaScript. В частности, если куки используются только для поддержки сеанса, то в JavaScript они не нужны, так что в этом случае следует устанавливать флаг HttpOnly:

Set-Cookie: PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; Secure; HttpOnly

Область видимости cookie

Директивы domain и path определяют область видимости куки, то есть те URL, к которым куки могут отсылаться.

  • Атрибут domain указывает хосты, к которым отсылаться куки. Если он не задан, то по умолчанию берется доменная часть документа (но без поддоменов). Если домен указан явно, то поддомены всегда включены. Например, если задано domain=server.com, то куки включены и в поддоменах, например, в blog.server.com.
  • Атрибут path указывает URL, который должен быть в запрашиваемом ресурсе на момент отправки заголовка. Символ «/» интерпретируется как разделитель разделов, подразделы также включаются. Если задано path=/docs, то подходят и такие пути, как /docs, /docs/web, /docs/web/http.

Работа с cookie из JavaScript

Куки можно создавать через JavaScript при помощи свойства document.cookie. Если флаг HttpOnly не установлен, то и доступ к существующим cookies можно получить через JavaScript.

// получить cookie
console.log(document.cookie);
PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; visitor=0d3749f09d222bea3b8f163937eb9bf1; lastvisit=1538919655
// установить cookie
document.cookie = "some_name=some_value";
console.log(document.cookie);
PHPSESSID=m2iut9i59p73ld1c5q9j49c6t0; visitor=0d3749f09d222bea3b8f163937eb9bf1; lastvisit=1538919655; some_name=some_value

Функция getCookie()

Следующая функция возвращает cookie с именем name:

// возвращает cookie с именем name, если есть, если нет, то undefined
function getCookie(name) {
    var matches = document.cookie.match(
        new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)")
    );
    return matches ? decodeURIComponent(matches[1]) : undefined;
}

Функция setCookie()

function setCookie(name, value, options) {
    options = options || {};

    var expires = options.expires;

    if (typeof expires == "number" && expires) {
        var d = new Date();
        d.setTime(d.getTime() + expires * 1000);
        expires = options.expires = d;
    }
    if (expires && expires.toUTCString) {
        options.expires = expires.toUTCString();
    }

    value = encodeURIComponent(value);

    var updatedCookie = name + "=" + value;

    for (var propName in options) {
        updatedCookie += "; " + propName;
        var propValue = options[propName];
        if (propValue !== true) {
            updatedCookie += "=" + propValue;
        }
    }

    document.cookie = updatedCookie;
}

Функция deleteCookie()

function deleteCookie(name) {
    // удаляем вызовом setCookie() с датой в прошлом
    setCookie(
        name,
        "",
        {expires: -1}
    )
}

Работа с cookie из PHP

Для сохранения cookie в браузере пользователя используется функция setcookie():

bool setcookie(
    string $name,
    string $value,
    int $expire, 
    string $path,
    string $domain,
    bool $secure,
    bool $httponly
);

Может принимать следующие параметры:

  • name: имя cookie, которое будет использоваться для доступа к его значению.
  • value: значение или содержимое cookie — любой алфавитно-цифровой текст не более 4 кБайт.
  • expire (необязательный параметр): срок действия, после которого cookie уничтожаются. Если данный параметр не установлен или равен 0, то уничтожение cookie происходит после закрытия браузера.
  • path (необязательный параметр): путь к каталогу на сервере, для которого будут доступны cookie. Если задать «/», cookie будут доступны для всего сайта. Если задать, например, /docs, cookie будут доступны из этого каталога и всех его подкаталогов (/docs/web, /docs/web/http). По умолчанию значением является текущий каталог, в котором устанавливаются cookie.
  • domain (необязательный параметр): задает домен, для которого будут доступны cookie. Если это домен второго уровня, например, server.com, то cookie доступны для всего сайта server.com, в том числе и для его поддоменов типа blog.server.com. Если задан поддомен blog.server.com, то cookie доступны только внутри этого поддомена.
  • secure (необязательный параметр): указывает на то, что значение cookie должно передаваться по протоколу HTTPS. Если задано true, cookie от клиента будет передано на сервер, только если установлено защищенное соединение. По умолчанию параметр равен false.
  • httponly (необязательный параметр): если равно true, cookie будут доступны только через HTTP протокол. То есть cookie в этом случае не будут доступны из JavaScript. По умолчанию параметр равен false.

Чтобы получить cookie, можно использовать глобальный массив $_COOKIE. Для удаления cookie достаточно в качестве срока действия указать какое-либо время в прошлом:

setcookie('lastvisit', '', time() - 3600);

Чтобы к идентификатору сессии PHPSESSID не было доступа из JavaScript, нужно отредактировать файл php.ini:

; Name of the session (used as cookie name).
; http://php.net/session.name
session.name = PHPSESSID

; Whether or not to add the httpOnly flag to the cookie, which makes
; it inaccessible to browser scripting languages such as JavaScript.
; http://php.net/session.cookie-httponly
session.cookie_httponly = 1

Можно также использовать функцию ini_set(), чтобы установит флаг HttpOnly уже во время выполнения приложения:

ini_set('session.cookie_httponly', 1);
session_start();

Еще одни способ изменить флаг HttpOnly — вызов функции session_set_cookie_params() перед session_start():

session_set_cookie_params(/*...*/);
session_start();

Установить флаг Secure для PHPSESSID из php.ini:

; http://php.net/session.cookie-secure
session.cookie_secure = 1

Установить флаг во время работы приложения:

ini_set('session.cookie_secure', 1);
session_start();
session_set_cookie_params(/*...*/);
session_start();

Поиск: Cookie • HTTP • HTTPS • JavaScript • PHP • Web-разработка • expire • httponly • localStorage • php.ini • secure • sessionStorage • setcookie

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.