Файлы cookie на локальном хосте с явным доменом

Я, должно быть, скучаю по некоторым элементам cookie. На localhost, когда я устанавливаю cookie на стороне сервера и указываю домен явно как localhost (или.localhost). куки не принимаются некоторыми браузерами.

Firefox 3.5: я проверил HTTP-запрос в Firebug. Что я вижу это:

Set-Cookie:
    name=value;
    domain=localhost;
    expires=Thu, 16-Jul-2009 21:25:05 GMT;
    path=/

или (когда я устанавливаю домен в.localhost):

Set-Cookie:
    name=value;
    domain=.localhost;
    expires=Thu, 16-Jul-2009 21:25:05 GMT;
    path=/

В любом случае, cookie не сохраняется.

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

Opera 9.64: и localhost, и.localhost работают, но когда я проверяю список файлов cookie в настройках, для домена устанавливается значение localhost.local, даже если он указан в списке localhost (в списке групп).

Safari 4: оба localhost и.localhost работают, но они всегда указаны в настройках как.localhost. С другой стороны, cookie без явного домена, он отображается как просто localhost (без точки).

В чем проблема с localhost? Из-за такого количества несоответствий должны существовать некоторые специальные правила, касающиеся localhost. Кроме того, мне не совсем понятно, почему домены должны начинаться с префикса? RFC 2109 прямо заявляет, что:

Значение атрибута Domain не содержит встроенных точек или не начинается с точки.

Зачем? В документе указывается, что это связано с безопасностью. Я должен признать, что я не прочитал всю спецификацию (возможно, сделаю это позже), но это звучит немного странно. Исходя из этого, установка куки на localhost будет невозможна.

25 ответов

Решение

По своему дизайну доменные имена должны иметь как минимум две точки; в противном случае браузер сочтет их недействительными. (См. Ссылку на http://curl.haxx.se/rfc/cookie_spec.html)

При работе на localhost, домен cookie должен быть полностью опущен. Просто установите его "" или же NULL или же FALSE вместо "localhost" недостаточно.

Для PHP см. Комментарии на http://php.net/manual/en/function.setcookie.php.

Если вы работаете с Java Servlet API, не вызывайте cookie.setDomain("...") метод вообще.

Я в целом согласен с @Ralph Buchfelder, но здесь приведено некоторое усиление этого экспериментом при попытке реплицировать систему с несколькими поддоменами (например, example.com, fr.example.com, de.example.com) на моей локальной машине (OS X / Apache / Chrome|Firefox).

Я отредактировал /etc/hosts, чтобы указать несколько мнимых поддоменов на 127.0.0.1:

127.0.0.1 localexample.com
127.0.0.1 fr.localexample.com
127.0.0.1 de.localexample.com

Если я работаю на fr.localexample.com и не указываю параметр домена, файл cookie правильно сохраняется для fr.localexample.com, но не отображается в других поддоменах.

Если я использую домен ".localexample.com", файл cookie правильно сохраняется для fr.localexample.com и виден в других поддоменах.

Если я использую домен "localexample.com" или когда я пробовал домен только "localexample" или "localhost", cookie не сохранялся.

Если я использую домен "fr.localexample.com" или ".fr.localexample.com", файл cookie правильно сохраняется для fr.localexample.com и (правильно) невидим в других поддоменах.

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

Если кто-то хочет попробовать это, вот несколько полезных кодов:

<html>
<head>
<title>
Testing cookies
</title>
</head>
<body>
<?php
header('HTTP/1.0 200');
$domain = 'fr.localexample.com';    // Change this to the domain you want to test.
if (!empty($_GET['v'])) {
    $val = $_GET['v'];
    print "Setting cookie to $val<br/>";
    setcookie("mycookie", $val, time() + 48 * 3600, '/', $domain);
}
print "<pre>";
print "Cookie:<br/>";
var_dump($_COOKIE);
print "Server:<br/>";
var_dump($_SERVER);
print "</pre>";
?>
</body>
</html>

localhost: вы можете использовать: domain: ".app.localhost" и это будет работать. Параметру 'domain' требуется 1 или более точек в имени домена для настройки файлов cookie. Тогда у вас могут быть сеансы, работающие в поддоменах localhost, например: api.app.localhost:3000,

Проблема межсайтовых файлов cookie, которую я решил следующим образом:

Бэкенд

Сторона сервера

  • обслуживается по адресу: http://localhost:8080
  • при создании ответа установите Cookie

атрибуты:

      SameSite=None; Secure; Path=/

Сторона клиента

Фронтенд (в моем случае Angular)

  • обслуживается на: http://localhost:4200/
  • при отправке запроса на сервер (бэкенд)

установить XHR.withCredentials=true:

      var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/', true);
xhr.withCredentials = true;
xhr.send(null);

Моя интерпретация:

  • когда внутренний и внешний домены различаются , решение о том, будут ли файлы cookie сохраняться в хранилище файлов cookie внешнего интерфейса, из полученного ответа принимается браузером. Браузер разрешит отправку файлов cookie ТОЛЬКО в том случае, если запрос XHR имеет и получены правильные атрибуты файлов cookie сервера (заголовок HTTP Set-Cookie).

  • когда внутренние и внешние домены различаются , решение о том, будут ли файлы cookie отправляться в запросе , принимается браузером. Браузер разрешит это, ТОЛЬКО если запрос XHR имеет

  • другими словами, если withCredentials=trueопущен - файлы cookie не будут отправлены в запросе и не будут получены и сохранены из ответа

  • полученные файлы cookie всегда хранятся под доменным именем внешнего интерфейса в хранилище файлов cookie браузера. В случае, если домен сервера отличается и файлы cookie успешно сохранены, эффект будет таким же, как если бы они были отправлены доменом внешнего интерфейса в первую очередь.

  • если атрибут cookie не указан, современный браузер (Firefox/Chrome) будет использовать значение по умолчанию Laxрежим, который слишком строг для межсайтовых файлов cookie

  • если атрибут cookie опущен - тогда SameSite=Noneбудет игнорироваться - необходимо установить

  • для локального хоста SecuredБраузер свойства cookie не требует HTTPS/SSL, будет работать http - нет необходимости обслуживать интерфейс или сервер под https://localhost ... РЕДАКТИРОВАТЬ 2022-03-02 - Для Safari (v15.1) это неверно -> в Safari http://localhost + cookie с безопасным - файл cookie будет игнорироваться, а не сохраняться в браузере (решение: для Safari + http://localhost удалить Secure и SameSite, если они предоставлены).

Советы по диагностике:

  • чтобы проверить, отправляются ли файлы cookie, откройте инструменты разработчика браузера и перейдите на вкладку «Сеть». Найдите запрос к серверной части и проверьте заголовки — найдите заголовок Cookie в заголовках запроса и Set-Cookie в заголовках ответа.
  • чтобы проверить, сохранены ли файлы cookie, откройте инструменты разработчика браузера, см. Диспетчер хранилища (Firefox), проверьте файлы cookie и найдите доменное имя внешнего интерфейса, проверьте, существует ли файл cookie, и если существует, проверьте, когда он был создан ...
  • не забудьте сначала установить CORS на бэкэнд

Ссылка: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie

Когда cookie установлен с явным доменом 'localhost' следующим образом...

Set-Cookie: имя = значение; домен = localhost; истекает = чт, 16 июля 2009 21:25:05 по Гринвичу; Путь = /

... тогда браузеры игнорируют его, потому что он не включает как минимум два периода и не является одним из семи специально обработанных доменов верхнего уровня.

... домены должны иметь по крайней мере два (2) или три (3) периода в них для предотвращения доменов в форме: ".com", ".edu" и "va.us". Любой домен, который выходит из строя в пределах одного из семи специальных доменов верхнего уровня, перечисленных ниже, требует только двух периодов. Любой другой домен требует как минимум три. Семь специальных доменов верхнего уровня: "COM", "EDU", "NET", "ORG", "GOV", "MIL" и "INT".

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

по крайней мере, один (1) или два (2) периода

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

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

Если вы устанавливаете cookie из другого домена (то есть вы устанавливаете cookie, отправляя запрос XHR с перекрестным происхождением), то вам необходимо убедиться, что вы установили withCredentials атрибут true в XMLHttpRequest, который вы используете для получения файла cookie, как описано здесь

Я потратил много времени на устранение этой проблемы сам.

Использование PHP, и ничего на этой странице не работает для меня. В конце концов я понял в своем коде, что параметр "secure" для PHP для session_set_cookie_params() всегда был установлен в TRUE.

Так как я не посещал localhost с https, мой браузер никогда не будет принимать cookie. Итак, я изменил эту часть своего кода, чтобы условно установить параметр "secure", основываясь на том, что $_SERVER['HTTP_HOST'] равен 'localhost' или нет. Работает хорошо сейчас.

Я надеюсь, что это помогает кому-то.

Мне повезло, когда я тестировал локально, используя 127.0.0.1 в качестве домена. Я не уверен почему, но у меня были смешанные результаты с localhost и.localhost и т. Д.

Результаты, которые я изменил в браузере.

Chrome-127.0.0.1 работал, но localhost .localhost и "" не работали. Firefox- .localhost работал, но localhost, 127.0.0.1 и "" - нет.

Не тестировали в Opera, IE или Safari

Единственное, что у меня сработало, это установить Path=/ на куки.

Более того, значение атрибута path по умолчанию, похоже, отличается от браузеров к браузерам, хотя я тестировал только два из них (Firefox и Chrome).

Chrome пытается установить cookie как есть; еслиpath атрибут опущен в Set-Cookie заголовок, то он не будет сохранен и проигнорирован.

Однако Firefox сохраняет cookie даже без явного pathатрибут. Он просто установил его с запрошенным путем; URL моего запроса был/api/v1/users и путь был установлен /api/v1 автоматически.

Так или иначе, оба браузера работали, когда path был установлен на / даже без явного домена, т.е. Domain=localhostили что-то. Таким образом, существуют некоторые различия в том, как каждый браузер обрабатывает файлы cookie.

После долгих экспериментов и чтения различных сообщений это сработало. Я мог установить несколько файлов cookie, прочитать их, установить отрицательное время и удалить их.

func addCookie(w http.ResponseWriter, name string, value string) {
    expire := time.Now().AddDate(0, 0, 1)
    cookie := http.Cookie{
       Name:    name,
       Value:   value,
       Expires: expire,
       Domain:  ".localhost",
       Path:    "/",
    }
    http.SetCookie(w, &cookie)
}

Вы можете использовать localhost.org или скорее .localhost.org это всегда разрешит 127.0.0.1

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

В конце концов, я просто удалил домен из cookie, если это localhost, и теперь он работает для меня в Chrome 38.

Предыдущий код (не работал):

document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';domain=.' + document.domain + ';path=/;';

Новый код (сейчас работает):

 if(document.domain === 'localhost') {
        document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';path=/;' ;
    } else {
        document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';domain=.' + document.domain + ';path=/;';
    }

Cookie необходимо указать SameSite атрибут, None значение использовалось по умолчанию, но последние версии браузеров Lax значение по умолчанию, чтобы иметь достаточно надежную защиту от некоторых классов атак с подделкой межсайтовых запросов (CSRF).

Вместе с SameSite=Lax вы также должны иметь Domain=localhost, поэтому ваш файл cookie будет связан с localhostи сохранил. Это должно выглядеть примерно так:

document.cookie = `${name}=${value}${expires}; Path=/; Domain=localhost; SameSite=Lax`;

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite

Кажется, есть проблема, когда вы используете https://<local-domain> а потом http://<local-domain>, http:// сайт не отправляет куки с запросами после https:// сайт устанавливает их. Принудительная перезагрузка и очистка кеша не помогают. Работает только ручная очистка куки. Кроме того, если я очистить их на https:// страницы, то http:// страница снова начинает работать.

Похоже, связано с "Строго безопасные куки". Хорошее объяснение здесь. Он был выпущен в Chrome 58 2017-04-19.

Похоже, что на самом деле Chrome записывает как безопасные, так и небезопасные файлы cookie, поскольку при нажатии на значок в адресной строке будут отображаться правильные файлы cookie в зависимости от протокола страницы.

Но Developer tools > Application > Cookies не будет отображать незащищенный файл cookie, когда существует безопасный файл cookie с тем же именем для того же домена, а также не будет отправлять незащищенный файл cookie с любыми запросами. Это похоже на ошибку Chrome, или, если ожидается такое поведение, должен быть какой-то способ просмотра безопасных файлов cookie при http страница и указание, что они переопределяются.

Обходной путь - использовать разные именованные куки-файлы в зависимости от того, предназначены ли они для http-сайта или https-сайта, и называть их в зависимости от вашего приложения. __Secure- Префикс указывает, что файл cookie должен быть строго безопасным, а также является хорошей практикой, поскольку безопасные и небезопасные не будут конфликтовать. У префиксов есть и другие преимущества.

Используя разные /etc/hosts домены для доступа https или http тоже подойдут, но один случайный https://localhost посещение предотвратит работу файлов cookie с такими же именами http://localhost сайты - так что это не хороший обходной путь.

Я подал отчет об ошибке Chrome.

Пробовал все варианты выше. Для меня сработало:

  1. Убедитесь, что для параметра withCredentials в запросе к серверу установлено значение true. XMLHttpRequest из другого домена не может устанавливать значения cookie для своего собственного домена, если для параметра withCredentials не задано значение true перед выполнением запроса.
  2. Не устанавливать Domain
  3. Задавать Path=/

Результат Set-Cookie заголовок:

Set-Cookie: session_token=74528588-7c48-4546-a3ae-4326e22449e5; Expires=Sun, 16 Aug 2020 04:40:42 GMT; Path=/

Существует проблема, связанная с открытием Chromium с 2011 года: если вы явно указываете домен как "localhost", вы должны установить его как false или же undefined,

У меня была аналогичная проблема, когда мой бэкэнд и внешний интерфейс работали на локальном хосте, но на разных портах. Чтобы исправить это, я опустил Domainв Set-Cookieи используется withCredentials: trueв моих вариантах запроса.

см. здесь

У меня была та же проблема, и я исправил ее, поместив 2 точки в самом имени файла cookie, не указав домен.

set-cookie: name.s1.s2=value; path=/; expires=Sun, 12 Aug 2018 14:28:43 GMT; HttpOnly

Благодаря ответу Саида , установка параметра cookie наdomain: ".localhost"иsecure: trueработал в Edge на macOS. Однако для того, чтобы Safari работал, мне пришлось установитьsecure: falseчто мешает Edge работать.

Другая важная деталь: expires = должен использовать следующий формат даты и времени: Wdy, DD-Mon-YYYY HH: MM: SS GMT ( RFC6265 - Раздел 4.1.1).

Set-Cookie:
  name=value;
  domain=localhost;
  expires=Thu, 16-07-2019 21:25:05 GMT;
  path=/

Я немного поиграл.

Set-Cookie: _xsrf=2|f1313120|17df429d33515874d3e571d1c5ee2677|1485812120; Domain=localhost; Path=/

работает в Firefox и Chrome на сегодняшний день. Однако я не нашел способа заставить его работать с curl. Я попробовал Host-Header и --resolve, не повезло, любая помощь приветствуется.

Тем не менее, он работает в curl, если я установил его

Set-Cookie: _xsrf=2|f1313120|17df429d33515874d3e571d1c5ee2677|1485812120; Domain=127.0.0.1; Path=/

вместо. (Который не работает с Firefox.)

Ни один из ответов здесь не работал для меня. Я исправил это, поместив свой PHP как самую первую вещь на странице.

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

С http://php.net/manual/en/function.setcookie.php

document.cookie = valuename + "=" + value + "; " + expires + "; домен =; путь =/";

это "домен =; путь =/"; будет принимать динамический домен, так как его cookie будет работать в поддомене. если вы хотите проверить в localhost, он будет работать

Если кто-то все еще сталкивается с этим, я обнаружил, что переход сpostнужен был запрос на запрос.

Я использовал axios, иwithCredentials: trueна интерфейсе, но это не удалось. Переключение запроса наgetи изменение моего бэкэнда, чтобы оно сработало.

Другие вопросы по тегам