如何正确使cookie过期?

How to properly expire cookie?

我们有一个网络服务,用户可以登录和注销。 Cookie 用于确定用户是否登录。

该服务公开了多个 "sites",每个都由一个子域标识。例如:

有两种登录方式; "service wide" 或 "site specific".

"Service wide" 登录请求被发送到一个特殊的子域 (http://globalauth.ourservice.com/)。此类登录请求会导致 Set-Cookie header,如下所示:

Set-Cookie: OUR-COOKIE=<<cookie-value>>; 
            expires=Wed, 03 May 2017 11:25:58 GMT; 
            domain=.ourservice.com; 
            path=/; 
            httponly

(此处添加换行符以方便阅读)

domain=.ourservice.com 设置使 cookie 可用于所有子域。

"Site specific" 登录请求被发送到站点特定的子域。它们导致 Set-Cookie header 如下所示:

Set-Cookie: OUR-COOKIE=<<cookie-value>>; 
            expires=Wed, 03 May 2017 11:23:42 GMT; 
            path=/; 
            httponly

注销请求总是发送到站点特定的子域,并且应该删除 "side wide" 登录和 "site specific" 登录的 cookie。

注销请求结果 Set-Cookie header 如下所示:

Set-Cookie: OUR-COOKIE=; 
            expires=Mon, 02 May 2016 11:26:54 GMT; 
            path=/; 
            httponly,
            OUR-COOKIE=; 
            expires=Mon, 02 May 2016 11:26:54 GMT; 
            domain=.ourservice.com; 
            path=/; 
            httponly

这里的想法是站点特定和服务范围的 cookie 都应该被清除和过期。

当使用 "service wide" 登录时有效,但当使用 "site specific" 登录时无效。

站点特定的 cookie 不会从浏览器中删除。

我们如何正确地指示浏览器 expire/remove cookie,无论它是否使用 domain 设置发布?

事实证明,这是由于 .NET Framework 4.0 和 4.5 中的 WCF-related 错误造成的。

规范 RFC 6265 不允许在单个 Set-Cookie header 中传输多个逗号分隔的 cookie。相反,应该使用多个 Set-Cookie header(每个 cookie 一个)。

我们正在使用 HttpResponseHeadersExtensions.AddCookies 添加 cookie。该方法的文档清楚地说:

Each Set-Cookie header is represented as one CookieHeaderValue instance.

然而,事实证明,多个 CookieHeaderValue 实例确实合并为一个,以逗号分隔,Set-Cookie header – 这是规范不支持的。

在 Whosebug 上查看以下相关 post:

引用后者post:

The fact that "Set-Cookie" is munged into a single cookie line is logged as a bug within Microsoft for .NET Framework 4.0 and also Framework 4.5. Within the Microsoft WCF development group, the bug is listed as "closed" and "won't fix".

According to Microsoft, the only workaround is to move from self-hosted to hosting within IIS and then using the (IIS) Response object directly (different code path that does not have the bug).

这对我们来说是个坏消息,因为我们目前只能使用 self-host 代码路径。我们必须找到解决此错误的方法。