Файлы 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.
Пробовал все варианты выше. Для меня сработало:
- Убедитесь, что для параметра withCredentials в запросе к серверу установлено значение true. XMLHttpRequest из другого домена не может устанавливать значения cookie для своего собственного домена, если для параметра withCredentials не задано значение true перед выполнением запроса.
- Не устанавливать
Domain
- Задавать
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 как самую первую вещь на странице.
Как и другие заголовки, куки должны отправляться до любого вывода из вашего скрипта (это ограничение протокола). Это требует, чтобы вы выполняли вызовы этой функции перед любым выводом, включая теги и любые пробелы.
document.cookie = valuename + "=" + value + "; " + expires + "; домен =; путь =/";
это "домен =; путь =/"; будет принимать динамический домен, так как его cookie будет работать в поддомене. если вы хотите проверить в localhost, он будет работать
Если кто-то все еще сталкивается с этим, я обнаружил, что переход сpost
нужен был запрос на запрос.
Я использовал axios, иwithCredentials: true
на интерфейсе, но это не удалось. Переключение запроса наget
и изменение моего бэкэнда, чтобы оно сработало.