带或不带域名的Cookie(浏览器不一致)

时间:2012-05-25 09:25:39

标签: c# cookies cross-browser

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

这将是相当长的,所以忍受我。

注意:我在我的主机文件中设置了一个名为" testdomain.com"的域名,这个 bug WONT在使用&时工作#34;本地主机"

注意2:我很想知道如果按照名称检索cookie,如果它提供了一系列cookie,那么它在Apache / PHP上是如何工作的。

维基百科

维基百科指出: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"。

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

  

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


到目前为止我?

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

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

结果如下:

IE9:1个cookie

IE with 1 cookie and domain explicitly set

Opera:1个cookie

Opera with 1 cookie and domain explicitly set

Firefox:1个Cookie

Firefox with 1 cookie and domain explicitly set

Chrome:1个Cookie

Chrome with 1 cookie and domain explicitly set

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

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

如果我使用以下代码:

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

});

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

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

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

火狐:

Firefox with 1 cookie and domain explicitly set

Chrome:

Chrome with 1 cookie and domain explicitly set

有趣的位

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

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会看到超过1个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 cookies set, the outcome

Opera - 设置了2个cookie(浏览器看到1):

enter image description here

Firefox - 2个Cookie集和浏览器看到2!:

enter image description here

Chrome - 2个Cookie设置,浏览器看到2个!:

enter image description here


现在你可能想知道wtf这一切。

嗯:

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

    我们必须更改身份验证,以便在我们将其推送时在Cookie中指定域。

    这打破了Chrome和Firefox,用户无法再登录,因为服务器会尝试验证旧的身份验证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,这会破坏多租户系统......

2 个答案:

答案 0 :(得分:9)

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

不要在.NET中使用明确的Cookie ...永远

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

吸取教训。不要使用明确的cookie。

答案 1 :(得分:5)

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

如果是Forms Authentication,请更改ASPXAUTH cookie的名称。