В какой части запроса правильнее передавать cookie
Перейти к содержимому

В какой части запроса правильнее передавать cookie

  • автор:

HTTP-куки

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

Куки часто используются для:

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

До недавнего времени куки использовались в качестве хранилища информации на стороне пользователя. Это могло иметь смысл в отсутствии вариантов, но теперь, когда в распоряжении браузеров появились различные API для хранения данных, это уже не так. Из-за того что куки пересылаются с каждым запросом, они могут ухудшать производительность (особенно при использовании мобильных сетей). В качестве хранилищ данных на стороне пользователя вместо них можно использовать Web storage API ( localStorage и sessionStorage ) и IndexedDB.

Примечание: Чтобы посмотреть сохранённые куки и другие хранилища данных, которые использует веб-страница, можно использовать Storage Inspector (Инспектор хранилища) в инструментах разработчика.

Создание куки

Получив HTTP-запрос, вместе с ответом сервер может отправить заголовок Set-Cookie . Куки обычно запоминаются браузером и посылаются в HTTP-заголовке Cookie (en-US) с каждым новым запросом к одному и тому же серверу. Можно задать срок действия кук, а также срок их жизни, после которого куки не будут отправляться. Также можно указать ограничения на путь и домен, то есть указать, в течении какого времени и к какому сайту они будут отсылаться.

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

Заголовок Set-Cookie HTTP-ответа используется для отправки куки с сервера в клиентское приложение (браузер). Простой куки может задаваться так:

Этот заголовок с сервера даёт клиенту указание сохранить куки (это делают, например, PHP, Node.js, Python и Ruby on Rails). Ответ, отправляемый браузеру, содержит заголовок Set-Cookie , и куки запоминается браузером.

Теперь с каждым новым запросом к серверу при помощи заголовка Cookie (en-US) браузер будет возвращать серверу все сохранённые ранее куки.

Сессионные cookie

Простой cookie, пример которого приведён выше, представляет собой сессионный cookie (session cookie) — такие cookie удаляются при закрытии клиента, то есть существуют только на протяжении текущего сеанса, поскольку атрибуты Expires или Max-Age для него не задаются. Однако, если в браузере включено автоматическое восстановление сеанса, что случается очень часто, cookie сеанса может храниться постоянно, как если бы браузер никогда не закрывался.

Постоянные cookies

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

Secure («безопасные») и HttpOnly куки

«Безопасные» (secure) куки отсылаются на сервер только тогда, когда запрос отправляется по протоколу SSL и HTTPS. Однако важные данные никогда не следует передавать или хранить в куках, поскольку сам их механизм весьма уязвим в отношении безопасности, а флаг secure никакого дополнительного шифрования или средств защиты не обеспечивает. Начиная с Chrome 52 и Firefox 52, незащищённые сайты (http:) не могут создавать куки с флагом Secure .

Куки HTTPonly не доступны из JavaScript через свойства Document.cookie API, что помогает избежать межсайтового скриптинга (XSS (en-US)). Устанавливайте этот флаг для тех кук, к которым не требуется обращаться через JavaScript. В частности, если куки используются только для поддержки сеанса, то в JavaScript они не нужны, так что в этом случае следует устанавливать флаг HttpOnly .

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

Директивы Domain и Path определяют область видимости куки, то есть те URL-адреса, к которым куки будут отсылаться.

Атрибут Domain

Атрибут Domain указывает хосты, на которые отсылаются куки. Если он не задан, то по умолчанию берётся доменная часть адреса документа (но без поддоменов). Если домен указан явно, то поддомены всегда включены.

Например, если задано Domain=mozilla.org , то куки включены и в поддоменах, например, в developer.mozilla.org .

Атрибут Path

Атрибут Path указывает URL, который должен быть в запрашиваемом ресурсе на момент отправки заголовка Cookie . Символ %x2F («/») интерпретируется как разделитель в URL-пути, подпути также будут учитываться.

Если задан Path=/docs , то совпадать будут следующие пути:

  • /docs
  • /docs/
  • /docs/Web/
  • /docs/Web/HTTP

А эти пути совпадать не будут:

  • /
  • /docsets
  • /fr/docs
Куки SameSite

Куки отправляются на сервер при любых запросах, даже если запрашивается статический ресурс с чужого сервера, то есть если происходит межсайтовый запрос. Например, если страница сайта site.com содержит изображение сайта site.net, при запросе изображения в запросе будут отправлены все куки пользователя для site.net. Чтобы ограничить отправку кук только тому сайту, которому они принадлежат, используют атрибут SameSite.

C помощью атрибута SameSite можно указать, когда и как отправлять куки с межсайтовыми запросами (где сайт определяется комбинацией домена и схемы http: или https: ). В некоторой степени этот атрибут защищает от межсайтовой подделки запроса (CSRF). SameSite может принимать три возможных значения: Strict , Lax и None .

С атрибутом Strict куки будут отправляться только тому сайту, которому эти куки принадлежат. Атрибут Lax работает похоже, но куки будут отправляться также при навигации на тот сайт, которому принадлежат куки. Например, при переходе по ссылке с внешнего сайта. Атрибут None отключает ограничение на отправку кук для межсайтовых запросов, но только в безопасном контексте (то есть если установлен SameSite=None , тогда также должен быть установлен атрибут Secure ). Если атрибут SameSite не установлен, куки будут восприниматься как Lax .

Примечание: В таблице совместимости (en-US) вы можете найти информацию о том, как обрабатываются атрибуты в конкретных версиях браузеров.

Куки с префиксами

Из-за дизайна механизма кук сервер не может подтвердить, что куки были отправлены с защищённого источника (secure origin), или быть уверенным в том, где именно они были установлены.

Уязвимое приложение поддомена может установить куку с атрибутом Domain , тем самым открывая к ней доступ на всех других поддоменнах. Этот механизм может эксплуатироваться с атакой фиксация сессии.

Примечание: Ознакомьтесь со статьёй фиксация сессии (en-US) , чтобы узнать об основных методах защиты от этой атаки.

Тем не менее в соответствии с принципом защита в глубину вы можете использовать куки с префиксами, чтобы гарантировать специфические факты о куках. Доступны два префикса:

Если в куке содержится этот префикс, она будет установлена заголовком Set-Cookie только в том случае, если кука будет содержать атрибут Secure и если запрос будет отправляться из защищённого источника. Также кука не должна включать атрибут Domain и должна содержать атрибут Path со значением / .

Если в куке содержится этот префикс, она будет установлена заголовком Set-Cookie только в том случае, если кука будет содержать атрибут Secure и если запрос будет отправляться из защищённого источника. Защита с помощью этого префикса слабее по сравнению с префиксом __Host- .

Браузеры будут отклонять установку этих кук, если они не будут удовлетворять всем ограничениям. Заметьте, что куки с префиксами, созданные в рамках поддомена, будут ограничиваться только им или будут полностью игнорироваться. Так как бэкенд проверяет только куки с заранее известными именами при авторизации пользователя или валидации CSRF-токена, куки с префиксами фактически работают как защитный механизм от фиксации сессии.

Примечание: Бэкенд веб-приложения обязан обращаться по полному имени куки, включая префикс. Пользовательские агенты не удаляют префикс из имени кук перед их отправкой в HTTP-заголовке Cookie (en-US) .

Для получения информации о статусе поддержки префиксов в разных браузерах обратитесь к статье про Set-Cookie .

Доступ из JavaScript с помощью Document.cookie

Куки можно создавать с помощью JavaScript, используя DOM-свойство Document.cookie . Также можно читать куки из JavaScript, если не был установлен атрибут HttpOnly .

Куки, созданные с помощью JavaScript, не могут содержать атрибут HttpOnly .

Пожалуйста, учитывайте вытекающие из этого проблемы, про которые рассказывается ниже в разделе Безопасность. Куки, доступные для JavaScript, могут быть похищены посредством XSS.

Безопасность

Примечание: При сохранении информации в куках имейте в виду, что у всех пользователей есть возможность просматривать и изменять их значения. В зависимости от типа приложения вы можете использовать ни о чём не говорящее имя для идентификатора кук, смысл которого будет понятен только бэкенду. Также вы можете рассмотреть возможность использования альтернативных механизмов аутентификации и конфиденциальности, например, JSON Web Tokens

Способы предотвращения атак, использующих куки:

  • Используйте атрибут HttpOnly для предотвращения доступа к кукам из JavaScript.
  • Куки, которые используются для хранения чувствительной информации, такой как аутентификационный токен, должны иметь короткое время жизни и атрибут SameSite , установленный в Strict или Lax . Для того чтобы узнать больше, смотрите раздел SameSite. В браузерах с поддержкой SameSite это гарантирует предотвращение отправки кук аутентификации с межсайтовыми запросами, фактически такие запросы с точки зрения бэкенда становятся неаутентифицированными.

Захват сессии (session hijacking) и XSS

Куки часто используются в веб-приложениях для идентификации аутентифицированного пользователя и сеанса работы. Соответственно, похищение кук из приложения может привести к захвату авторизованного сеанса пользователя. Кража кук часто осуществляется посредством социальной инженерии (Social Engineering) и использования уязвимости XSS (en-US).

Атрибут HttpOnly помогает уменьшить эту угрозу, перекрывая доступ к кукам из JavaScript.

Межсайтовая подделка запроса (CSRF — Cross-site request forgery)

В Wikipedia есть хороший пример CSRF. В сообщение, например, в чате или на форуме, включают «изображение», которое, на самом деле, представляет собой запрос к серверу банка на снятие денег:

Если вы аутентифицированны в своём банковском аккаунте, а куки по-прежнему действительны (и никакой дополнительной проверки не требуется), то при загрузке HTML-документа форума или чата с этим изображением деньги будут переведены с вашего счета. Для защиты от этого используется ряд методов:

  • Как и при XSS (en-US), важна фильтрация входящей информации.
  • Для любой чувствительной операции должно запрашиваться подтверждение.
  • Куки, используемые для чувствительных операций, должны иметь короткий срок действия.
  • Дополнительную информацию можно получить в пользовательской инструкции по предотвращению CSRF на сайте OWASP.

Трекинг и приватность

Сторонние (Third-party) куки

Куки ассоциируются с определённым доменом и схемой (такой как http: или https: ). Также они могут быть ассоциированы с поддоменом с помощью атрибута Domain . Если домен и схема кук совпадает с доменом и схемой текущей страницы, на которой вы находитесь, то их называют собственными куками (first-party cookies). Если домен и схема кук отличается от домена и схемы текущей страницы, то такие куки называют сторонними куками (third-party cookies).

Сервер, хостящий страницу, устанавливает собственные куки, но на странице могут находиться изображения и другие компоненты с других доменов (например, баннерная реклама), они в свою очередь могут устанавливать сторонние куки. Сторонние куки часто используются для рекламы и трекинга пользователей в сети. Как пример, можете посмотреть куки, которые устанавливает Google.

Третья сторона, контролирующая внедрение сторонних кук, может создать профиль пользователя на основе истории его посещений разных сайтов с помощью кук, отправляемых одним и тем же браузером с разных сайтов. Firefox по умолчанию блокирует сторонние куки, про которые известно, что они используются для трекинга пользователей. Сторонние куки (или просто куки для трекинга) могут также быть заблокированы другими настройками браузера или расширениями. Блокировка кук в некоторых ситуациях может стать причиной некорректного поведения сторонних компонентов, например, виджетов социальных сетей.

Примечание: Бэкенд может (и должен) устанавливать у кук атрибут SameSite (en-US) для управления отправкой кук на сторонние серверы.

Законодательство, связанное с куки

Регулирующие акты и законодательство, покрывающие куки, включают:

  • General Data Privacy Regulation (GDPR) в Европейском Союзе
  • ePrivacy Directive в Европейском Союзе
  • California Consumer Privacy Act в Штате Калифорния

Эти акты и директивы действуют глобально. Они применяются ко всем сайтам во Всемирной паутине, к которым пользователи из данных юрисдикций получают доступ (Европейский Союз и Калифорния, с оговоркой, что Калифорнийский закон применяется к компаниям с доходом выше 25 миллионов долларов и несколькими другими оговорками).

Эти акты и директивы включают такие требования как:

  • Сообщать пользователям, что сайт использует куки.
  • Давать возможность пользователям отказываться от получения всех или некоторых кук.
  • Давать возможность пользователям использовать основные функции вашего сервиса без получения кук.

Могут существовать другие законодательные акты, которые применимы к вашей локальной юрисдикции. На вас лежит ответственность знать про них и следовать им. Существуют компании, которые предлагают код с «куки баннером» и берут на себя заботы о следовании законодательству, связанному с куками.

Другие способы хранения информации в браузере

Другой способ для хранения данных в браузере — Web Storage API. Свойства window.sessionStorage и window.localStorage подобны сессионным и постоянным кукам, но позволяют хранить больше данных и никогда не отправляются на сервер. Для хранения ещё большего объёма структурированных данных может использоваться IndexedDB API или библиотеки, построенные поверх него.

Существуют техники для повторной установки кук после их удаления. Такие куки называются куки-зомби. Эти техники нарушают принципы приватности пользователей и пользовательского контроля и могут нарушать законодательства, регулирующие приватность данных, соответственно, использующий их сайт подвержен судебному разбирательству.

Cookies — Протокол HTTP

Изначально работать с HTTP было не очень просто. Дело в том, что это протокол без сохранения состояния, то есть каждый запрос-ответ не связан с предыдущим запросом-ответом. Это было неудобно, потому что иногда нам приходится запоминать информацию: например об аутентификации пользователя или о товарах в его корзине в интернет-магазине.

Тут возникает проблема: «Как запомнить, что это тот пользователь, с которым мы только что работали?». Решение этой проблемы было найдено когда был придуман механизм, который называется Cookie.

В этом уроке мы разберемся, что такое куки и как они работают.

Как работают куки

Давайте сделаем запрос к сайту Хекслета и посмотрим, как этот механизм работает. Мы будем использовать программу curl . Она позволяет делать HTTP-запросы и управлять различными их параметрами с помощью флагов. При работе с curl нам не нужно заранее устанавливать соединение и потом набирать сырой запрос. Достаточно сразу определить параметры, и curl сама отправит все нужные заголовки запроса, в том числе и по HTTPS.

Давайте выполним запрос для получения только заголовков, для этого добавим к запуску curl флаг —head:

Мы видим два заголовка, которые занимаются установкой cookie — set-cookie. Обратите внимание, что каждая cookie посылается в отдельном заголовке. Таких заголовков может быть достаточно много.

Изнутри кука представляет собой пару ключ=значение и отделяется от дополнительных параметров точкой с запятой. Куки сохраняются в браузере на клиенте и при следующем запросе он отправляет их обратно на сервер. Непосредственно в браузере они никак не используются.

Хорошая аналогия — это как получить номерок в гардеробе и потом вернуть его, чтобы понять какая куртка ваша. При этом сам номерок никакой ценности не представляет, и его нельзя использовать самостоятельно.

Куки делятся как минимум на два типа: сессионные и постоянные.

Сессионные куки

Сессионные куки в нашем запросе не устанавливаются, так как мы видим дополнительные параметры в заголовке set-cookie. Если бы их не было, то кука называлась бы сессионной. Основное их отличие от постоянных в том, что такая кука удаляется при закрытии браузера. Наглядный пример — это механизм работы галочки «запомнить меня». Если вы авторизуетесь и не отметите эту галочку, а потом закроете браузер и снова зайдете на сайт, то будете не авторизованы. Так происходит потому, что используется сессионная кука.

Постоянные куки

Вернемся к запросу выше. В этом случае устанавливаются постоянные куки. Они сохраняются на жестком диске — место их хранения может быть разным в зависимости от браузера. Такие куки отличаются от сессионных тем, что можно управлять длиной их жизни при помощи параметра expires:

В параметре expires указывается дата удаления куки, после которой она не будет отсылаться на сервер. Стоит сказать, что есть еще один параметр, который используется для тех же целей — MAX-AGE. В его значении указывается количество секунд, по истечении которых кука будет удалена:

Так как часть браузеров не поддерживают MAX-AGE, некоторые фреймворки часто устанавливают сразу оба параметра и браузеры просто игнорируют тот, который им не нужен. Таким образом заголовок set-cookie, который содержит два параметра MAX-AGE и expires, считается валидным. В стандарте также говорится, что регистр имени куки не имеет значения.

Параметры domain и path

Также можно установить еще несколько параметров. Параметры domain и path задают область видимости куки — это URL, на которые кука может отправляться. Если они не заданы, то по умолчанию кука будет пересылаться на сервер только для текущего пути и домена. В нашем примере в path указан корень сайта, то есть кука будет отправляться для всех страниц:

Обратите внимание на одну важную деталь в этом примере. Если установлен domain=.hexlet.io, то кука будет работать не только для всех страниц сайта, но и для всех поддоменов — при этом наличие точки перед именем домена не имеет значения. Если мы совсем не установим параметр domain, то кука для поддоменов работать не будет, хотя по умолчанию значение домена будет hexlet.io.

Уникальность куки определяется тремя параметрами key (имя куки), domain и path. Это значит, что если какую-то куку нужно переустановить, то при следующем запросе в set-cookie эти параметры должны совпадать. Если хотя бы один из них отличается, то будет установлена новая кука.

Удаление куки

Заголовка для удаления куки не существует. Чтобы удалить ее, нужно установить нулевой или отрицательный MAX-AGE, либо задать expires в прошлом, тогда кука будет немедленно удалена.

HttpOnly cookie

Можно заметить, что в нашем примере установлен дополнительный параметр HttpOnly. HttpOnly-куки передаются с AJAX-запросами, но их нельзя получить через JavaScript на странице сайта. Это дополнительный уровень безопасности от XSS-атак.

Отправка на сервер

Мы обновляем страницу в браузере. После этого происходит отправка следующего заголовка:

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

Ультимативный гайд по HTTP. Cookies и CORS

Привет! Меня зовут Ивасюта Алексей, я техлид команды Bricks в Авито в кластере Architecture, а это мой цикл статей о протоколе HTTP. В первой части мы уже познакомились с версией протокола 1.0 и поговорили о структуре ответов и запросов. Теперь пришло время узнать, что такое Cookies и для чего нужен CORS.

Cookies

HTTP — это протокол без сохранения состояния. Это значит, что когда на сервер поступают два запроса, он не понимает: их послал один клиент или разные. В реальных приложениях постоянно надо идентифицировать пользователя: проверять, авторизован ли он, выводить пользовательские рекомендации, хранить корзину выбранных товаров в магазине. Для этого есть механизм Cookies.

Cookies — это фрагмент данных, в которых сервер передаёт важную информацию о клиенте. Браузер получает этот фрагмент, сохраняет его и с каждым последующим запросом отсылает обратно на сервер. Так он понимает, от какого клиента пришёл запрос.

Куки выглядят, как пара ключ=значение . Для их установки сервер должен в ответе на запрос клиента прислать заголовок Set-Cookie со значением.

Как только браузер получит его в ответ на запрос, он сохранит значение куки в Cookie Storage. В каждый последующий запрос браузер будет добавлять сохранённые значения в заголовке Cookie .

Пример выше — это сессионный куки, для них не указываются сроки хранения. Он будет существовать, пока пользователь не закроет вкладку с сайтом в браузере. Но многие браузеры используют механизм восстановления сессий, поэтому сессионные куки теоретически могут жить вечно.

Обычно кукам устанавливается фиксированное время жизни. Это можно сделать двумя способами:

установить дату истечения срока годности — Expires ,

установить количество секунд, по истечении которых кука перестанет быть актуальной — MAX_AGE .

Допустим, срок жизни куки из предыдущего примера должен истечь 1 января 2030 года. Тогда нужно прислать заголовок со значением куки и датой истечения срока годности, разделёнными точкой с запятой.

Теперь с наступлением 1 января 2030 года кука станет невалидной и удалится.

В альтернативном варианте срок жизни куки должен истечь через две минуты. Тогда вместо даты нужно прислать количество секунд в параметре MAX_AGE :

Разные браузеры могут использовать разные параметры для установки времени жизни куки. Поэтому зачастую сервер присылает оба варианта, а браузер сам выбирает поддерживаемый параметр.

Стандарт RFC6265 1 , описывает куки. Он закрепляет правило, что имена параметров — регистронезависимые. Поэтому эта запись тоже будет валидной:

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

Параметры domain и path управляют областью видимости куки и определяют, на каких поддоменах и для каких URL они будут работать. Если не указать параметр domain , то он по умолчанию будет равен хосту сайта, например, example.com. Тогда куки не будут работать для поддоменов, например, test.example.com . Если указать значение domain , то куки будет работать для хоста и всех поддоменов.

Параметр path указывает, по каким URL при запросе ресурсов необходимо передавать куку в заголовке. Если установить path=/ , то куки будут отправляться для всех запросов. Если указать значение path=/api , то они будут передаваться для всех запросов на ресурсы, URL которых начинается с /api .

Расширим предыдущий пример:

Уникальный идентификатор куки — их ключ (в примере — token), значения domain и path . Если нужно переопределить значение ранее установленных куки, то эти три параметра должны совпадать. В противном случае браузер создаст новые. А ещё не существует метода для удаления куки. Можно только установить её повторно и указать дату истечения срока годности expires в прошлом или нулевой или отрицательный max_age .

Защита Cookies

Куки представляют два параметра, которые защищают их от различных атак.

Параметр secure говорит о том, что такие куки будут отсылаться только по HTTPS-соединению. Если сайт работает по HTTP, то значение не будет передано. Secure не обеспечивает дополнительного шифрования, поэтому не стоит хранить чувствительные данные в куках.

Параметр httpOnly создаёт куки, к которым нельзя обратиться из кода JavaScript в браузере. Так можно избежать XSS-атак. 2

Отправка на сервер

Куки отправляются на сервер при каждом запросе, если не подошла их дата истечения срока годности и параметры path и domain соответствует URL ресурса. Они передаются одной строкой в значении заголовка запроса Cookie и разделяются точкой с запятой.

Директива Евросоюза о Cookie

25 мая 2011 года в силу вступила Директива 2009/136/EC Евросоюза о куки. 3 Она требует запрашивать разрешение пользователя на получение и использование информации с его компьютера. Поэтому почти каждый сайт при первом посещении или после очистки кеша выводит баннер с запросом на использование Cookies.

По умолчанию в браузере действует политика безопасности Same Origin Policy. Это означает, что доступ к ресурсам можно получить, только если источник этих ресурсов и источник запроса совпадают. Это сделано для того, чтобы некий сайт хакеров evil.com не мог получить доступ, например, к почтовому ящику на домене gmail.com и прочитать письма. Эта стратегия работала долгое время, когда JavaScript считался браузерным языком для украшения страничек и не умел делать AJAX-запросы.

Со временем разработчики поняли, что хотят уметь отправлять данные на сервер и получать их при помощи асинхронных запросов. Но политика Same Origin не позволяет сделать этого. После долгих обсуждений был предложен механизм CORS — Cross-Origin Resource Sharing.

Этот механизм использует дополнительные HTTP-заголовки. С ним браузер пользователя получает разрешения на доступ к выбранным ресурсам, если домен сайта и домен запрашиваемого ресурса отличаются.

Например, сайт находится на домене example.com . Запрос отправляется на сайт, который находится на домене web-server.com . Для начала браузер должен понять, сложный этот запрос или простой. Простой запрос отправляется методом GET , POST или HEAD и содержит только следующие заголовки:

Content-Type со значением application/x-www-form-urlencoded , multipart/form-data или text/plain .

Остальные запросы считаются сложными. Например, если он отправляется методом DELETE или содержит заголовок Authorization . Простые запросы браузер отправляет напрямую на сервер и автоматически добавляет к ним заголовок Origin . Его значение равно URL хоста, с которого отправляется запрос. В нашем примере это Origin: https://example.com .

Сервер принимает такой запрос и определяет, разрешить хосту получить этот ресурс или отказать в запросе. Для этого в ответе используется специальный заголовок Access-Control-Allow-Origin . Он определяет, с каких источников разрешено принимать запросы. Если указать Access-Control-Allow-Origin: http://example.com , то запрос на ресурс будет всегда разрешён только домену example.com . Если нужно разрешить получать ресурс с любого домена, то в ответе на запрос должен быть заголовок Access-Control-Allow-Origin: * .

Браузер заблокирует ответ на запрос, если:

сервер вернёт в ответе заголовок Access-Control-Allow-Origin: null ,

значение не будет совпадать с переданным в заголовке запроса Origin ,

не будет заголовка.

Если браузер обнаружит сложный запрос, то сначала отправит серверу preflight — предварительный запроc при помощи HTTP-метода OPTIONS . В запрос при этом добавляется заголовок Access-Control-Request-Method , в значении которого указывается HTTP-метод оригинального запроса.

Если в оригинальном запросе передаются заголовки не из списка разрешённых, то в запрос OPTIONS дополнительно добавляется заголовок Access-Control-Request-Headers . В его значении через запятую перечисляются все заголовки оригинального запроса.

В случае отправки preflight-запроса сервер также должен вернуть заголовок Access-Control-Allow-Origin с необходимым значением.

Если в запрос добавлен заголовок Access-Control-Request-Method , то сервер в ответе должен указать, какие HTTP-методы разрешено использовать для запроса ресурса в заголовке ответа Access-Control-Allow-Methods .

Если в запрос добавлен заголовок Access-Control-Request-Headers , то сервер в ответе должен указать, какие HTTP-заголовки разрешено использовать для запроса ресурса в заголовке ответа Access-Control-Allow-Headers .

Пример ответа на preflight-запрос:

Браузер получает ответ и после этого сверяет значения Origin , разрешенных заголовков и методов. Если всё совпадает, отправляет оригинальный запрос на сервер. Если разрешённые параметры не совпадают с фактическими, браузер блокирует отправку оригинального запроса и сообщает об ошибке.

Иногда необходимо уметь передавать Cookies при обращении к другим доменам. Заголовок Cookie не относится к списку разрешенных и попадает под политику безопасности. Чтобы их можно было передавать, сервер в ответ на preflight и на оригинальный запрос должен возвращать заголовок Access-Control-Allow-Credentials: true . Для работы куки также нужно возвращать в заголовке Access-Control-Allow-Origin конкретное значение разрешённого хоста.

Ответ от кроссдоменного запроса получен. Допустим, нужно получить доступ к заголовкам в коде JavaScript в браузере и прочитать их значения. Сделать это не так просто, потому что по умолчанию доступ из Java Script для кроссдоменных запросов есть только к следующим заголовкам:

Если JS попытается прочитать значение другого заголовка, то получит null. Но сервер в ответе на запрос может перечислить заголовки, к которым можно получить доступ из Javascript в заголовке Access-Control-Expose-Headers . Заголовки указываются через запятую. Например, Access-Control-Expose-Headers: Authorization, X-Version .

Заголовок ответа сервера Access-Control-Max-Age сообщает браузеру, насколько предзапрос может быть кэширован и опущен при запросах к серверу. Значение указывается в секундах. Если после первого выполнения preflight-запроса время жизни Max-Age не вышло, то повторной отправки не будет. Оригинальный запрос выполнится сразу.

Про Cookies и CORS на этом — всё. В третьей статье цикла я расскажу о нововведениях в версии HTTP/1.1 и чем она отличается от HTTP/2.

HTTP cookie

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.

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

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

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

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

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

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

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

Функция getCookie()

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

Функция setCookie()
Функция deleteCookie()

Работа с cookie из PHP

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

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

  • 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 достаточно в качестве срока действия указать какое-либо время в прошлом:

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *