本地主机上具有显式域的 Cookie
Posted
技术标签:
【中文标题】本地主机上具有显式域的 Cookie【英文标题】:Cookies on localhost with explicit domain 【发布时间】:2010-11-11 04:21:27 【问题描述】:我一定错过了一些关于 cookie 的基本知识。在 localhost 上,当我在服务器端 和 设置 cookie 时,将域明确指定为 localhost(或 .localhost)。某些浏览器似乎不接受 cookie。
Firefox 3.5:我在 Firebug 中检查了 HTTP 请求。我看到的是:
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:我没有使用任何额外的工具,但是 cookie 似乎也没有被存储,因为它没有在后续请求中被发回。
Opera 9.64: localhost 和 .localhost 工作,但是当我在 Preferences 中检查 cookie 列表时,域设置为 localhost.local,即使它已列出在 localhost 下(在列表分组中)。
Safari 4: localhost 和 .localhost 都可以使用,但它们总是在 Preferences 中列为 .localhost。另一方面,没有显式域的 cookie,它仅显示为 localhost(无点)。
本地主机有什么问题?由于存在如此多的不一致,因此必须有一些涉及 localhost 的特殊规则。另外,我不完全清楚为什么域必须以点为前缀? RFC 2109 明确指出:
域属性的值 不包含嵌入的点或不包含 以点开头。
为什么?该文件表明它必须做一些与安全有关的事情。我不得不承认我没有阅读完整的规范(以后可能会这样做),但这听起来有点奇怪。基于此,在 localhost 上设置 cookie 是不可能的。
【问题讨论】:
6 年的线程,这仍然是一个问题。我正在使用 Chrome v40。见here。 11年过去了,还是不行,2020年饼干还是个痛点! 这可能无法回答问题。在 chrome 版本 80 中,您可以在chrome://flags
中禁用“没有 SameSite 的 Cookie 必须是安全的”,以允许使用 SameSite=None
或 SameSite=Lax
而不仅仅是安全。
我认为从现在开始我们可以在 Firefox 83.0 中做到这一点,但在 chrome 87 中仍然不行
【参考方案1】:
根据设计,域名必须至少有两个点;否则浏览器会认为它们无效。 (参考http://curl.haxx.se/rfc/cookie_spec.html)
在处理localhost
时,cookie 域必须完全省略。您不应将其设置为 ""
或 NULL
或 FALSE
而不是 "localhost"
。这还不够。
对于 php,请参阅http://php.net/manual/en/function.setcookie.php#73107 上的 cmets。
如果使用 Java Servlet API,则根本不要调用 cookie.setDomain("...")
方法。
【讨论】:
我在 RFC6265 中没有看到关于域中的两个点的任何地方:tools.ietf.org/html/rfc6265#section-5.2.3 .Net 说为本地域中的所有主机将其设置为“.local”。这似乎与 Opera/Safari msdn.microsoft.com/en-us/library/ckch3yd2.aspx 一致 在 PHP 等语言中,null 和 false 等价于空字符串。将 cookie 域设置为空字符串有效。我在我的项目中使用此设置。 @Justin:嗯,你可能需要在设置cookie时完全省略Domain=
参数。如果您只是将域设置为 null 或空,那么您的框架可能会发送带有该值的Domain=
参数,而不是忽略它?检查例如萤火虫。
@MandoMando 域中的两个点是标准的,localhost 是***域。这就是 localhost.lvh.me 存在的原因
这有点措辞不当。 “设置为 null 或 false 或空字符串”应改为“根本不设置 cookie 的“域”部分。”例如,使用简单的测试完全省略 cookie 的域部分适用于 localhost:((domain && domain !== "localhost") ? ";domain="+domain : "")
【参考方案2】:
我大致同意@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>
【讨论】:
【参考方案3】:localhost: 您可以使用:domain: ".app.localhost"
,它会起作用。 'domain' 参数需要在域名中包含 1 个或多个点,用于设置 cookie。然后,您可以让会话跨 localhost 子域工作,例如:api.app.localhost:3000
。
【讨论】:
还在express.session(cookie: domain: '.app.localhost', maxAge: 24 * 60 * 60 * 1000 )
express.session(cookie: domain: '.app.localhost', maxAge: 24 * 60 * 60 * 1000 )
中使用 Express 3.x 在 node.js 服务器上进行了测试和工作
如果您使用的是本地域,则应选择此作为答案!在子域之前加一个点可以解决我的问题。
那么,.app.
的前缀来自哪里?它是某个 SPEC 的一部分吗?它是否适用于所有不合格的域(那些没有两个点的域)?另外,这适用于旧浏览器吗? :^)
哦...我现在明白了...这只是愚弄浏览器的伎俩。好的。【参考方案4】:
当 cookie 设置为 'localhost' 的显式域时...
设置 Cookie:名称=值; 域=本地主机;到期=格林威治标准时间 2009 年 7 月 16 日星期四 21:25:05;路径=/
...然后浏览器会忽略它,因为它是does not include at least two periods and is not one of seven specially handled, top level domains。
...域中必须至少包含两 (2) 或三 (3) 个句点 阻止以下形式的域:“.com”、“.edu”和“va.us”。任何域 在列出的七个特殊***域之一中失败 下面只需要两个句点。任何其他域至少需要 三。七个特殊的***域是:“COM”、“EDU”、“NET”、 “ORG”、“GOV”、“MIL”和“INT”。
请注意,上面的句点数可能假定需要前导句点。然而,这段时间是ignored in modern browsers,它可能应该是……
至少一 (1) 或两 (2) 个 个句点
请注意,域属性的默认值为the host name of the server which generated the cookie response。
所以没有为 localhost 设置 cookie 的解决方法是简单地不指定域属性并让浏览器使用默认值 - 这似乎与显式值没有相同的约束在域属性中确实如此。
【讨论】:
我没有DV,但我猜其他人这样做的原因是因为您的回答并没有真正增加太多价值。两个时期的要求和将域属性留空都已在其他答案中讨论过。此外,您添加的有关***域的内容似乎不正确。根据我的经验,这不是必需的。 @TTT 不确定您是否在我的回答中谈到了我说它应该至少是 1 或 2 个句点,具体取决于 TLD,因为前导句点被忽略了?因此,我提供了有关该问题的一些背景知识,并添加了一个我认为其他地方没有涵盖的要点——显式域的规则与浏览器默认使用的规则不同。似乎它为我增加了一些价值。 将域保留为空(根本不设置它)不会导致 Chrome 保留 localhost 的 cookie。它仍然忽略它。请注意,这仅适用于“永久”cookie(设置过期日期的),因为它将挂在本地主机的“会话”cookie(不设置过期日期的)上。【参考方案5】:如果您要设置来自另一个域的 cookie(即通过发出 XHR 跨源请求来设置 cookie),那么您需要确保在用于获取的 XMLHttpRequest 上将 withCredentials
属性设置为 true here描述的cookie
【讨论】:
是的,即使这样。它仍然不适用于跨域请求。浏览器 - Safari,IE 11【参考方案6】:结果因浏览器而异。
Chrome- 127.0.0.1 工作但 localhost .localhost 和 "" 没有。 Firefox- .localhost 有效,但 localhost、127.0.0.1 和 "" 无效。
尚未在 Opera、IE 或 Safari 中测试过
【讨论】:
刚刚用 Chrome V.22.0.1229.94 m 测试了它:为 localhost 设置 cookie 而不提供Domain=
参数有效。 Domain=
也有效,但 Domain=localhost
无效。
Domain=localhost
在这里适用于 Chrome 和 Firefox,只要记住在 axios 中设置标志 withCredentials: true
,或者相当于你的 http 客户端 js。【参考方案7】:
我自己花了很多时间解决这个问题。
使用 PHP,但此页面上的任何内容都不适合我。我最终在我的代码中意识到PHP's session_set_cookie_params() 的“安全”参数始终设置为 TRUE。
由于我没有使用 https 访问 localhost,我的浏览器永远不会接受 cookie。因此,我修改了我的那部分代码,以根据 $_SERVER['HTTP_HOST'] 是否为“localhost”有条件地设置“安全”参数。现在工作得很好。
我希望这对某人有所帮助。
【讨论】:
【参考方案8】:您可以使用localhost.org
或更确切地说是.localhost.org
,它将始终解析为127.0.0.1
【讨论】:
我建议不要在安全方面这样做,因为localhost.org
是一个指向127.0.0.1
的实际域。我们对所有者了解不多,他们只能通过将指向地址更改为恶意 IP 来劫持流量。
肯定是缺点
或者你可以设置你自己的域指向127.0.0.1
【参考方案9】:
唯一对我有用的是在 cookie 上设置 Path=/
。
此外,路径属性的默认值似乎因浏览器而异,尽管我只测试了其中两个(Firefox 和 Chrome)。
Chrome 尝试按原样设置 cookie;如果path
属性在Set-Cookie
标头中被省略,则它不会被存储和忽略。
然而,即使没有明确的path
属性,Firefox 也会存储一个 cookie。它只是用请求的路径设置它;我的请求网址是/api/v1/users
,路径自动设置为/api/v1
。
无论如何,当path
设置为/
时,即使没有明确的域,即Domain=localhost
或其他东西,两个浏览器都可以工作。所以各个浏览器处理cookies的方式会有一些不同。
【讨论】:
【参考方案10】:使用 127.0.0.1 作为域进行本地测试时,我的运气要好得多。我不知道为什么,但我对 localhost 和 .localhost 等的结果好坏参半。
【讨论】:
【参考方案11】:没有一个建议的修复对我有用 - 将其设置为 null、false、添加两个点等 - 不起作用。
最后,如果它是 localhost,我只是从 cookie 中删除了域,现在它在 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=/;';
【讨论】:
【参考方案12】:当您使用https://<local-domain>
然后http://<local-domain>
时似乎有问题。在https://
站点设置它们之后,http://
站点不会发送带有请求的 cookie。强制重新加载和清除缓存没有帮助。只有手动清除 cookie 有效。另外,如果我在https://
页面上清除它们,那么http://
页面将重新开始工作。
看起来与“严格的安全 cookie”有关。很好的解释here。 2017 年 4 月 19 日是released in Chrome 58。
看起来 Chrome 确实记录了安全 cookie 和非安全 cookie,因为它会在单击地址栏图标时根据页面的协议显示正确的 cookie。
但是Developer tools > Application > Cookies
在同一个域有同名的安全cookie时不会显示非安全cookie,也不会随任何请求发送非安全cookie。这似乎是一个 Chrome 错误,或者如果这种行为是意料之中的,那么在 http
页面上应该有一些方法可以查看安全 cookie,并指示它们被覆盖。
解决方法是根据它们是用于 http 站点还是 https 站点来使用不同的命名 cookie,并将它们命名为特定于您的应用程序。 __Secure-
前缀表示 cookie 应该是严格安全的,这也是一个很好的做法,因为安全和非安全不会冲突。前缀也有other benefits。
对 https 和 http 访问使用不同的 /etc/hosts
域也可以,但是一次意外的 https://localhost
访问会阻止任何同名的 cookie 在 http://localhost
站点上工作 - 所以这不是一个好的解决方法。
我已经提交了Chrome bug report。
【讨论】:
【参考方案13】:经过大量实验和阅读各种帖子后,这很有效。我可以设置多个 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”、“.localhost”,似乎没有任何效果。 我最终使用了 Alex Edwards 会话管理器(在我的情况下使用 mysql,但他为您提供了其他选项),效果很好。您可能要考虑相同的alexedwards.net/blog/scs-session-manager 我修改了 /etc/hosts 以使用 localhost.com,它也可以正常工作。【参考方案14】:有一个issue on Chromium open since 2011,如果您明确将域设置为'localhost',则应将其设置为false
或undefined
。
【讨论】:
这是唯一对我有用的解决方案,设置Domain: undefined
和 Path: '/'
【参考方案15】:
我遇到了同样的问题,我通过在 cookie 名称本身中添加 2 个点而不指定任何域来解决它。
set-cookie: name.s1.s2=value; path=/; expires=Sun, 12 Aug 2018 14:28:43 GMT; HttpOnly
【讨论】:
【参考方案16】:尝试了以上所有选项。对我有用的是:
-
确保对服务器的请求将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=/
【讨论】:
【参考方案17】: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
【讨论】:
【参考方案18】:document.cookie = valuename + "=" + value + "; " + expires + ";domain=;path=/";
这个“域=;路径=/”;将采用动态域,因为它的 cookie 将在子域中工作。 如果你想在 localhost 中测试它会起作用
【讨论】:
【参考方案19】:这里没有一个答案对我有用。我通过将我的 PHP 作为页面中的第一件事来修复它。
与其他标头一样,cookie 必须在脚本的任何输出之前发送(这是协议限制)。这要求您在任何输出之前调用此函数,包括和标记以及任何空格。
来自http://php.net/manual/en/function.setcookie.php
【讨论】:
这与问题无关,这只是在标题之前发送任何其他输出的错误【参考方案20】:我玩了一下。
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。)
【讨论】:
【参考方案21】:另一个重要细节,expires= 应使用以下日期时间格式:Wdy, DD-Mon-YYYY HH:MM:SS GMT (RFC6265 - Section 4.1.1) .
Set-Cookie:
name=value;
domain=localhost;
expires=Thu, 16-07-2019 21:25:05 GMT;
path=/
【讨论】:
-1 当前的 cookie 规范是 RFC 6265,tools.ietf.org/html/rfc6265,其中明确规定允许使用 4 位数年份。因此,使用 2 位数年份是个坏主意,不同的浏览器会有不同的解释。 正确。参考 RFC6265 第 4.1.1 节 正确,但早在 2011 年 6 月我没有找到这个 RFC。所以虽然这个信息现在不正确,但当我写的时候不是。 不要小看它,事情会发生变化,我们都需要帮助确保答案保持最新。只需使用@sleske 为您提供的最新信息更新您的答案,并感谢他的帮助。【参考方案22】:我遇到了类似的问题,我的后端和前端在本地主机上运行,但端口不同。为了解决这个问题,我在Set-Cookie
中省略了Domain
,并在我的请求选项中使用了withCredentials: true
。
见here
【讨论】:
【参考方案23】:我这样解决的跨站点 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 存储中。仅当 XHR 请求具有 withCredentials=true
并且收到正确的服务器 Cookie 属性(HTTP Set-Cookie 标头)时,浏览器才允许发送 cookie
当后端域和前端域不同时,cookie 是否将在请求中发送由浏览器决定。仅当 XHR 请求具有 withCredentials=true
换句话说,如果 withCredentials=true
被省略 - cookie 将不会在请求中发送 NOR 将从响应中接收并保存
收到的 cookie 总是存储在前端域名下在浏览器 cookie 存储中。如果服务器域不同,cookies保存成功,效果和前端域先发送一样。
如果SameSite=None
cookie 属性被省略,今天的浏览器 (Firefox/Chrome) 将使用默认的 Lax
模式,这对于跨站点 cookie 来说过于严格
如果 Secured
cookie 属性被省略 - 那么 SameSite=None
将被忽略 - 它需要设置 Secured
对于 localhost Secured
cookie 属性浏览器不需要 HTTPS / SSL,http 可以工作 - 无需在 https://localhost ...
下提供前端或后端
诊断提示:
为了检查 cookie 是否已发送 - 打开浏览器开发人员工具并检查网络选项卡。找到后端的请求并检查 Headers - 在 Request headers 中搜索 Cookie header,在 Response headers 中搜索 Set-Cookie 为了检查 cookie 是否已保存 - 打开浏览器开发工具,查看存储管理器 (Firefox),检查 Cookie 并搜索前端域名,检查 cookie 是否存在,如果存在,请检查它的创建时间.. . 别忘了先在后端设置 CORS参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
【讨论】:
以上是关于本地主机上具有显式域的 Cookie的主要内容,如果未能解决你的问题,请参考以下文章