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

Phi*_*ill 44 c# cookies cross-browser

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

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

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

注意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")
{

});
Run Code Online (Sandbox Code Playgroud)

我们应该获得一个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
});
Run Code Online (Sandbox Code Playgroud)

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

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

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


和我一起到目前为止?

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

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

这是结果:

IE9:1个cookie

IE与1 cookie和域明确设置

Opera:1个cookie

Opera明确设置了1个cookie和域

Firefox:1个cookie

Firefox明确设置了1个cookie和域

Chrome:1个Cookie

已明确设置1个Cookie和域名的Chrome

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

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

如果我使用以下代码:

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

});
Run Code Online (Sandbox Code Playgroud)

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

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

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

火狐:

Firefox明确设置了1个cookie和域

铬:

已明确设置1个Cookie和域名的Chrome

有趣的位置

这是它变得有趣的地方.如果我像这样一个接一个地写饼干:

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

});
Run Code Online (Sandbox Code Playgroud)

个人我希望浏览器中存在一个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>
Run Code Online (Sandbox Code Playgroud)

这些是结果:

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

IE  -  2个cookie设置,结果

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

在此输入图像描述

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

在此输入图像描述

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

在此输入图像描述


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

好:

  1. 当您通过C#中的Name访问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;
}
Run Code Online (Sandbox Code Playgroud)

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

无论如何它都不能使用,因为域没有被推回到带有cookie的服务器.

更新2

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

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

Phi*_*ill 9

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

不要在.NET中使用Explicit cookies ...永远

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

课程是学到的.不要使用显式cookie.


Wil*_*BZA 5

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

在Forms Authentication的情况下,更改ASPXAUTH cookie的名称.