【问题标题】:Logout via Set-Cookie fails通过 Set-Cookie 注销失败
【发布时间】:2013-12-07 12:35:28
【问题描述】:

我们不久前将我们的网站转移到了一个新的主机上,并且偶尔会遇到人们无法再注销的问题。不确定这是否与托管环境或代码更改有关。

这是相关位的 Wireshark 日志 - 所有都发生在同一个 TCP 流中。

  1. 来自浏览器的注销请求(注意身份验证 cookie):

    GET /cirrus/logout HTTP/1.1
    
    Host: subdomain.domain.com
    
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    
    Accept-Language: en-US,en;q=0.5
    
    Accept-Encoding: gzip, deflate
    
    Referer: http://subdomain.domain.com/cirrus/CA/Admin/AccountSwitch
    
    Cookie:  USER.AUTH=AOvDEjH3w6xIxUC0sYNOAQR5BZ7pPmEF0RMxqohERN87Ti03Eqxd7rQC/BveqmaszmFg8QoSonP+Z+mtQQivKpvloFsQYretYKR8ENubj+moUBF479K5e4albKxS9mBEWT5Xy/XCnEyCPqLASGLY09ywkmIilNU1Ox4J3fCtYXHelE/hyzuKe9y3ui5AKEbbGs3sN9q1zYjVjHKKiNIGaHvjJ2zn7ZUs042B82Jc9RHzt0JW8dnnrl3mAkN1lJQogtlG+ynQSCyQD8YzgO8IpOnSXLJLaCMGMQcvSyX4YKJU/9sxgA5r5cZVCkHLsReS3eIJtXoxktMO6nxVZJY6MX1YwuJOgLRQvwBy9FFnQ6ye
    
    X-LogDigger-CliVer: client-firefox 2.1.5
    
    X-LogDigger: logme=0&reqid=fda96ee5-2db4-f543-81b5-64bdb022d358&
    
    Connection: keep-alive
    
  2. 服务器响应。它清除 cookie 值并重定向

    HTTP/1.1 302 Found
    
    Server: nginx
    
    Date: Fri, 22 Nov 2013 14:40:22 GMT
    
    Content-Type: text/html; charset=utf-8
    
    Content-Length: 124
    
    Connection: keep-alive
    
    Cache-Control: private, no-cache="Set-Cookie"
    
    Location: /cirrus
    
    Set-Cookie: USER.AUTH=; expires=Fri, 22-Jul-2005 14:40:17 GMT; path=/cirrus
    
    X-Powered-By: ASP.NET
    
    X-UA-Compatible: chrome=IE8
    
    
    
    <html><head><title>Object moved</title></head><body>
    
    <h2>Object moved to <a href="/cirrus">here</a>.</h2>
    
    </body></html>
    
  3. 浏览器遵循重定向,但使用旧的 cookie 值:

    GET /cirrus HTTP/1.1
    
    Host: subdomain.domain.com
    
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    
    Accept-Language: en-US,en;q=0.5
    
    Accept-Encoding: gzip, deflate
    
    Referer: http://subdomain.domain.com/cirrus/CA/Admin/AccountSwitch
    
    Cookie: USER.AUTH=AOvDEjH3w6xIxUC0sYNOAQR5BZ7pPmEF0RMxqohERN87Ti03Eqxd7rQC/BveqmaszmFg8QoSonP+Z+mtQQivKpvloFsQYretYKR8ENubj+moUBF479K5e4albKxS9mBEWT5Xy/XCnEyCPqLASGLY09ywkmIilNU1Ox4J3fCtYXHelE/hyzuKe9y3ui5AKEbbGs3sN9q1zYjVjHKKiNIGaHvjJ2zn7ZUs042B82Jc9RHzt0JW8dnnrl3mAkN1lJQogtlG+ynQSCyQD8YzgO8IpOnSXLJLaCMGMQcvSyX4YKJU/9sxgA5r5cZVCkHLsReS3eIJtXoxktMO6nxVZJY6MX1YwuJOgLRQvwBy9FFnQ6ye
    
    X-LogDigger-CliVer: client-firefox 2.1.5
    
    X-LogDigger: logme=0&reqid=0052e1e1-2306-d64d-a308-20f9fce4702e&
    
    Connection: keep-alive
    

Set-Cookie 标头中是否有任何明显的缺失可能会阻止浏览器删除 cookie?

要更改现有 cookie 的值,以下 cookie 参数必须匹配:

  • 姓名
  • 路径

名称和路径是明确设置的,域不是。会不会是这个问题?

编辑:因为有人问过为什么过期日期设置在过去,所以需要更多背景信息。 这是使用 AppHarbor 安全插件的轻微修改:https://github.com/appharbor/AppHarbor.Web.Security 修改是包含 cookie 的路径。请在此处找到修改后的注销方法:

public void SignOut(string path)
    {
        _context.Response.Cookies.Remove(_configuration.CookieName);
        _context.Response.Cookies.Add(new HttpCookie(_configuration.CookieName, "")
        {
            Expires = DateTime.UtcNow.AddMonths(-100),
            Path = path
        });
    }

过去的过期日期由 AppHarbor 插件完成,是常见的做法。见http://msdn.microsoft.com/en-us/library/ms178195(v=vs.100).aspx

【问题讨论】:

  • 丢弃cookie服务器端而不是客户端不是更明智吗?
  • 这样做实际上更安全,持续会话只会暴露风险。

标签: authentication cookies logout


【解决方案1】:

很好的问题,很好的笔记。我最近也遇到了这个问题。

除了您应该已经做的事情之外,还有一种故障安全方法:

  • 将过期时间设置为过去。
  • 设置路径域。
  • 将虚假数据放入要删除的 cookie 中!

Set-Cookie: USER.AUTH=invalid; expires=Fri, 22-Jul-2005 14:40:17 GMT; path=/cirrus; domain=subdomain.domain.com

故障安全方法如下:

在所有 cookie 的末尾添加一个特殊的字符串。除非该字符串存在,否则拒绝 cookie 并强制重置它。例如,所有新的 cookie 必须如下所示:

Set-Cookie: USER.AUTH=AOvDEjH3w6xIxUC0sYNOAQR5BZ7pPmEF0RMxqohERN87Ti03Eqxd7rQC/BveqmaszmFg8QoSonP+Z+mtQQivKpvloFsQYretYKR8ENubj+moUBF479K5e4albKxS9mBEWT5Xy/XCnEyCPqLASGLY09ywkmIilNU1Ox4J3fCtYXHelE/hyzuKe9y3ui5AKEbbGs3sN9q1zYjVjHKKiNIGaHvjJ2zn7ZUs042B82Jc9RHzt0JW8dnnrl3mAkN1lJQogtlG+ynQSCyQD8YzgO8IpOnSXLJLaCMGMQcvSyX4YKJU/9sxgA5r5cZVCkHLsReS3eIJtXoxktMO6nxVZJY6MX1YwuJOgLRQvwBy9FFnQ6ye|1386510233; expires=Fri, 22-Jul-2005 14:40:17 GMT; path=/cirrus; domain=subdomain.domain.com

注意变化:存储在USER.AUTH 中的极长字符串以|1386510233 结尾,这是设置cookie 时的unix 纪元。

这为 cookie 解析增加了一个简单的额外步骤。现在您需要测试| 的存在并丢弃unix epoch,除非您想知道cookie 的设置时间。为了让它更快,您可以只检查 string[length-10]==| 而不是解析整个字符串。在我这样做的方式中,我将字符串拆分为|,并在拆分后检查两个值。这绕过了一个由两部分组成的解析过程,但这方面是特定于语言的,并且在您选择策略时确实是优先考虑的。如果您打算丢弃该值,只需检查您期望 | 所在的特定索引。

以后如果您再次更改主机,您可以测试那个 unix epoch 并拒绝早于某个时间点的 cookie。这最多会为您的 cookie 处理程序添加两个额外的进程:删除 |unixepoch 并且如果需要,如果您再次更改主机,则检查何时拒绝 cookie。这会在页面加载中增加大约0.001s,或者更少。与客户服务失败和大规模脑损伤相比,这是值得的。

您的新 cookie 策略允许您立即轻松拒绝所有没有 |unixepoch 的 cookie,因为您知道它们是旧 cookie。是的,人们可能会抱怨这种方法,但它是真正知道 cookie 有效的唯一方法,真的。您不能依赖客户端为您提供有效的 cookie。除非您想存储大量数据,否则您无法记录每一个 cookie。如果您将每个 cookie 都存储起来,并且每次都检查它,那么可以将 0.01s 添加到页面加载中,而不是在此策略中使用 0.001s,因此存储路径不值得。

另一种方法是使用 USER.AUTHENTICATION 而不是 USER.AUTH 作为新的 cookie 值,但这可能更具侵入性。如果/当您再次更改主机时,您不会从我上面所说的中受益。

祝你过渡顺利。我希望你能解决这个问题。使用上面的策略,我能够做到。

【讨论】:

  • 非常感谢。似乎是最好的解决方案。我希望找出处理 cookie 的方式有什么问题——但据我所知,这取决于某些浏览器对此的解释不同。您的故障安全方法 defo 应该可以工作。
  • 我非常高兴这个策略对你有帮助,你明白为什么我的方法有优点了。它不一定“漂亮”,但它总是有效的!
【解决方案2】:

过去我们在删除 cookie 时遇到过问题,是的,域和路径必须与您尝试删除的 cookie 的域和路径匹配。

尝试在HttpCookie 中设置正确的域和路径。

【讨论】:

    【解决方案3】:

    我猜我会说历史过期日期导致整个 Set-Cookie 行被忽略(为什么要设置一个 8 年前过期的 cookie?)。

    expires=Fri, 22-Jul-2005

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-06
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 2020-02-10
    • 2018-03-18
    • 1970-01-01
    • 2021-03-14
    相关资源
    最近更新 更多