50

我注意到浏览器之间在 cookie 方面存在一些真正的不一致。

这将是相当长的,所以请耐心等待。

注意:我在我的主机文件中设置了一个名为“testdomain.com”的域,这个错误在使用“localhost”时不会起作用。

注意2:我很想知道这在 Apache/PHP 上是如何工作的,如果您按名称检索 cookie,如果它返回一组 cookie。

维基百科

维基百科指出:http ://en.wikipedia.org/wiki/HTTP_cookie#Domain_and_Path

域和路径
cookie 域和路径定义了 cookie 的范围——它们告诉浏览器 cookie 应该只针对给定的域和路径发送回服务器。如果未指定,则默认为所请求对象的域和路径。

因此,如果我们向下推:

Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

我们应该得到一个 cookie,使用的域是来自请求对象的域,在这种情况下它应该是“testdomain.com”。

W3

W3 在 cookie 规范中声明:http: //www.w3.org/Protocols/rfc2109/rfc2109

域=域

选修的。Domain 属性指定 cookie 对其有效的域。 明确指定的域必须始终以点开头。

因此,如果我们向下推:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});

我们明确地向下推主机名,我们应该在 cookie 上设置一个域名,该域名将以点为前缀,在这种情况下它应该是“.testdomain.com”。

它还说明了维基百科上的内容:

域默认为请求主机。(请注意,request-host 的开头没有点。)


跟我到现在?

如果我使用第一种方法,定义一个域:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});

这是结果:

IE9:1个cookie

具有 1 个 cookie 和域的 IE 显式设置

歌剧:1个饼干

Opera 明确设置了 1 个 cookie 和域

火狐:1个cookie

明确设置了 1 个 cookie 和域的 Firefox

铬:1个饼干

明确设置了 1 个 cookie 和域的 Chrome

如您所见,Opera 和 IE 都设置了一个没有点前缀的 EXPLICIT 域。

Firefox 和 Chrome 都使用点前缀设置 EXPLICIT 域。

如果我使用以下代码:

Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

IE / Opera:两者的结果完全相同,没有点前缀的域。

有趣的是,Firefox 和 Chrome 都创建没有点前缀的 cookie。

(我清除了所有 cookie 并再次运行代码)

火狐:

明确设置了 1 个 cookie 和域的 Firefox

铬合金:

明确设置了 1 个 cookie 和域的 Chrome

有趣的位

这就是有趣的地方。如果我像这样一个接一个地写饼干:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});
Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

就我个人而言,我希望浏览器中存在一个 cookie,因为我认为它是基于 cookie 名称的。

这是我观察到的:

在 IE / Opera 中,LAST cookie 集是使用的 cookie。这是因为 Cookie 名称和域名相同。

如果您用点显式定义域名,两个浏览器仍会看到 1 个 cookie,即最后一个同名 cookie。

另一方面,Chrome 和 Firefox 会看到多个 cookie:

我编写了以下 JavaScript 将值转储到页面:

<script type="text/javascript">

(function () {
    var cookies = document.cookie.split(';');
    var output = "";

    for (var i = 0; i < cookies.length; i++) {
        output += "<li>Name " + cookies[i].split('=')[0];
        output += " - Value " + cookies[i].split('=')[1] + "</li>";
    }

    document.write("<ul>" + output + "</ul>");
})();

</script>

这些是结果:

IE - 2 cookie 集(浏览器看到 1):

IE - 2 cookie 设置,结果

Opera - 2 个 cookie 集(浏览器看到 1):

在此处输入图像描述

Firefox - 设置了 2 个 cookie,浏览器看到 2!:

在此处输入图像描述

Chrome - 2 个 cookie 设置和浏览器看到 2!:

在此处输入图像描述


现在你可能想知道这一切都是什么。

好:

  1. 当您在 C# 中按名称访问 cookie 时,它​​会为您提供 1 个 cookie。(第一个具有该名称的 cookie)
  2. 浏览器将所有 cookie 发送到服务器
  3. 除了 cookie 的键/值之外,浏览器不会发送任何信息。(这意味着服务器不关心域)
  4. 如果您通过索引检索它们,您可以访问同名的两个 cookie

问题...

当我们按下它时,我们必须更改我们的身份验证以在 cookie 中指定域。

这破坏了 Chrome 和 Firefox,用户不再能够登录,因为服务器会尝试验证旧的 auth cookie。这是因为(据我了解)它使用身份验证 Cookie 名称来检索 cookie。

即使有两个 cookie,第一个被检索到恰好是旧的,身份验证失败,用户没有登录。有时正确的 cookie 是列表中的第一个,并且身份验证成功......

最初,我们通过推送一个带有旧域的 cookie 来解决这个问题。这适用于 Chrome 和 Firefox。

但它现在破坏了 IE/Opera,因为两种浏览器都不关心域,只根据名称比较 cookie。

我的结论是,cookie 上的域完全是浪费时间。

假设我们必须指定域,并且我们不能依赖用户清除他们的浏览器缓存。我们如何解决这个问题?

更新:

深入研究 .NET 如何注销用户。

if (FormsAuthentication._CookieDomain != null)
{
    httpCookie.Domain = FormsAuthentication._CookieDomain;
}

看起来表单身份验证完全有可能推送过期的 Auth cookie,这与用户通过身份验证的 cookie 完全无关。它不使用当前 Auth Cookie 的域。

无论如何它都不能使用它,因为域没有通过 cookie 推回服务器。

更新 2

看来 FormsAuthentication 真的坏了。如果在对用户进行身份验证时在 cookie 上使用显式域名,请等待会话超时,然后刷新页面,FormsAuthentication 使用的生成 cookie 的方法会导致域为 null,从而导致浏览器分配一个无点域。

它需要预先为表单分配一个域才能将其分配给 cookie,这会破坏多租户系统......

4

2 回答 2

10

@WilliamBZA 的建议帮助解决了最初的问题,但随后导致 cookie 创建隐式域 cookie 的注销/会话超时错误使我得出结论,解决方案是......

不要在 .NET 中使用显式 cookie ...永远

问题太多了,肯定可以通过在表单/域、Cookie/域等上显式来解决。确保在任何地方都使用正确的域。但是,如果您的应用程序托管多个域或者是多租户,那么它就变得太成问题了。

吸取了教训。不要使用显式 cookie。

于 2012-06-01T08:36:39.317 回答
5

无法帮助解释为什么对 cookie 进行不同处理,但快速解决方法是为每个子应用程序使用不同的 cookie 名称,而不是使用 cookie 的域。

在表单身份验证的情况下,更改 ASPXAUTH cookie 的名称。

于 2012-05-26T08:03:00.697 回答