在302重定向期间发送浏览器Cookie

118

在302重定向时返回cookie是否存在任何问题?例如,如果我创建一个return-to-url cookie并在同一响应中重定向用户,是否会有任何(现代)浏览器忽略该cookie?


阅读了一些内容后,我认为会话变量比Cookie更好,因为它们是服务器端的,不依赖于客户端的可预测性。 - ADTC
9个回答

65
根据这篇博客文章:http://blog.dubbelboer.com/2012/11/25/302-cookie.html ,所有主流浏览器,包括Windows和Mac上的IE(6, 7, 8, 9, 10),FF(17),Safari(6.0.2)和Opera(12.11),在重定向时都会设置cookie。这适用于301和302重定向。
如Benni所指出的那样:https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies 同站点属性(SameSite)是cookie的一个属性,它指定cookie是否应限制在第一方或同站点上下文中。 SameSite允许几个值:
  • "SameSite=Strict"属性的cookie仅随同站点请求发送。
  • "SameSite=Lax"属性的cookie将与同站点请求一起发送,或者与具有“安全”的HTTP方法的跨站点顶级导航一起发送。
  • "SameSite=None"属性的cookie将与同站点和跨站点请求一起发送。

2
不幸的是,这个列表不包括Chrome,所以我们不能完全说“所有”主要浏览器... - MestreLion
3
在我的Chrome浏览器上它可以工作。所以,我认为我们可以说现在它终于能够在2019年正常工作了。 - Michael
3
取决于 SameSite 策略:即使是严格模式,它仍然不起作用。 - Benni
1
为了保护更多的网站和用户,新的默认安全模式假定所有的cookie都应该受到保护,除非另有规定。开发人员必须使用一个新的cookie设置SameSite=None来指定跨站点访问的cookie。 - Ritesh
1
在那个被称为Safari的“主要”浏览器上,可能存在错误,即使设置了SameSite=Lax,也无法设置cookie:https://bugs.webkit.org/show_bug.cgi?id=219650 - Brecht De Rooms

54

一条通知(为了拯救开发人员的生命):

当cookie的域名是localhost时,IE和Edge会忽略重定向响应中的Set-Cookie。

解决方案:

使用127.0.0.1代替localhost


14
IE和Edge可能已经“修复”了这个问题,所以它们也不会为127.0.0.1设置cookie。唉!他们想知道为什么开发人员并不都喜欢IE... 你的答案让我省去了大约4个小时的苦思冥想。谢谢! - GlenPeterson
1
在 Chrome 版本 92.0.4515.159 (官方版本) (x86_64) 上遇到了这个问题。 - Anton Yurchenko
1
请使用 lvh.me 域名代替 127.0.0.1。它允许您添加子域名,例如 subdomain.lvh.me - Dmitry

45

1
您指定的论坛页面无法通过URL访问。您是指IE6和Windows Mobile浏览器无法访问吗? - hiroshi
1
链接已移动。我设置了一个新链接,内容基本相同。我指的是IE特定版本的移动版会添加自己的一套错误。 - regilero

21

最近我们遇到了这个问题(2022年3月)——Firefox和Chrome在HTTP 302重定向时都没有立即设置cookies。

详情如下:

  • 我们发送了带有"SameSite=Strict"策略的Set-Cookie头和指向同一域的不同路径的Location的HTTP 302重定向。
  • 然而,即使请求是同一域的(第一方请求),浏览器在随后的GET请求(重定向的Location)中也没有发送Cookie。
  • 我们可以从浏览器存储检查选项卡中看到Cookie,但在302响应之后的请求中却没有它。
  • 当我们刷新页面(或在地址栏中输入网址并按回车键)时,一切都正常工作,因为Cookie会在所有随后的请求中正确发送。
  • 我们认为这可能是一个bug / 未记录的行为。就好像浏览器把cookie“存储得有点晚”。

我们通过提供带有客户端重定向的HTTP 200来解决了这个问题:

<!DOCTYPE html>
<html>
<head><meta http-equiv="refresh" content="0; url='REDIRECT_URL'"></head>
<body></body>
</html>

另一种解决方法是将SameSite设置为Lax(或删除它,它将默认为Lax)。 - Uladzimir Shchur
2
@UladzimirShchur 移除 SameSite=strict 不是解决方法。我会称其为一种变通方法,因为它完全改变了 Cookie 的安全上下文。 - Vojtech Vitek - golang.cz
我有同样的问题,但我没有使用SameSite标志。 我有一个页面,可以登录用户并重定向他们,从url中删除日志参数(使用Location 302头)。 这可能是用户访问的第一页。10个请求中,有1个无法捕获PHPSESSID cookie,登录失败,第二个页面报告未经授权的错误。 我已转储了第一页的响应标题和第二个页面的请求标题,并验证了Set-Cookie是否存在但未发送回(其他cookies存在)。 我看不到其他使用meta redirect的方法。 - c3k
这个Chromium bug描述了一个类似的问题,但它不能可靠地重现(因此关闭wontfix)。对我们来说,meta refresh方法起作用了。 - tangle

21

这里是关于此问题的Chromium bug报告(HTTP响应的状态码为302时,设置cookie被忽略)。


1
如果这是真的,那确实是一个非常糟糕的消息 :-( - MestreLion
我认为他们已经修复了它。虽然错误报告仍然显示“不予修复”,但在我的Chrome浏览器上它可以工作。 - Michael
2
@Michael 注意,Chromium 不等同于 Chrome:https://www.lifewire.com/chromium-and-chrome-differences-4172101 - 这意味着虽然它可能在 Chrome 上运行,但这并不一定适用于 Chromium。 - Thomas

15

我刚刚遇到了这个问题,无论是在Firefox还是Safari中都出现了这个问题,但是在Chrome中没有。根据我的测试,这种情况只会发生在重定向期间域名发生变化的情况下。这在OAuth2流程中是很典型的:

  1. OAuth2身份提供者(GitHub、Twitter、Google)将浏览器重定向回您的应用程序
  2. 您的应用程序的回调URL验证授权并设置登录cookie,然后再次重定向到目标URL
  3. 您的目标URL在没有任何cookie的情况下加载。

出于我还没有弄清楚的原因,有些来自第二个请求的cookie被忽略了,而另一些则没有。但是,如果请求2返回一个带有Refresh头(“meta refresh”重定向)的HTTP 200,则通过请求3正确设置cookie。


8
我怀疑 OAuth 回调问题的原因是 samesite=strict。对于回调请求,浏览器仍然认为发起者是谷歌(或您使用的任何 OAuth 提供程序)。因此,如果您在 302 响应中设置了一个 samesite=strict 的 cookie,那么浏览器可能会认为“啊哈!这是一个来自谷歌到您网站的跨站请求”,因此在请求重定向的 URL 时不会发送 cookie。解决方法是像您已经做的那样使用 meta-refresh,这样您的请求就来自您自己的站点。我可能说得不好,但这是我的目前想法。 - Ilan
@Ilan 哇,谢谢你。我有点怀疑是这个问题,但是你的评论证实了我的想法。 - DOMZE
1
我遇到了这个问题。绝对没有任何组合的“SameSite”、“Domain”、“Secure”能够可靠地将 cookie 与重定向一起发送... - Joe
1
对我来说,将cookie从sameSite: 'strict'更改为'lax'就解决了问题。感谢提示。 - Kitson
同样的问题 - 在重定向到oauth页面之前设置cookie是有效的,但在重定向回UI之前在oauth回调路由上设置cookie无效。将SameSite更改为lax或none对我来说都不起作用。 - Dominic
显示剩余2条评论

11

这是一种不被推荐的方法,但如果您真的不想依赖于30x set-cookie浏览器行为,您可以在设置cookie时使用HTML meta http-equiv="refresh"“重定向”。例如,在PHP中:

<?php
    ...
    setcookie("cookie", "value", ...);
    url="page.php";
?>
<html>
<head><meta http-equiv="refresh" content=1;url="<?=$url?>"></head>
<body><a href="<?=$url?>">Continue...</a></body>
</html>

服务器将使用200而不是正确的300x重定向发送Set-Cookie,因此浏览器将存储cookie,然后执行"重定向"。 <a>链接是一种备用方法,以防浏览器不执行元刷新。


4
在使用OpenIdConnect / IdentityServer在.Net上时遇到了这个问题,其中一个单独的API(不同的主机名)处理身份验证并重定向回主站。

首先(为了在本地开发环境中),您需要将CookieSecure选项设置为SameAsRequestNever以处理http://localhost/不安全的情况。请参见Michael Freidgeim的答案。

其次,您需要将CookieSameSite属性设置为Lax,否则cookie根本不会被保存。Strict在这里无效!


2
稍微澄清一下 - cookie 确实被保存了。只是它们不会被发送到下一个请求,所以看起来好像它们没有被保存。 - jjnguy

1
在我的情况下,我设置CookieOptions.Secure=true, 但在http://localhost上测试它,并且浏览器根据设置隐藏cookie。
为避免这种问题,您可以将cookie的Secure选项设置为匹配协议Request.IsHttps,例如。
new CookieOptions()
                {
                    Path = "/",
                    HttpOnly = true,
                    Secure = Request.IsHttps,
                    Expires = expires
                }

4
在这种情况下不要设置安全标志。该标志的整个作用是告诉浏览器仅在通过HTTPS连接时使用Cookie。有条件地设置标志会改变语义,且在从HTTPS -> HTTP过渡时会失去Cookie,但在从HTTP -> HTTPS过渡时不会失去。所有这些都与浏览器在302重定向上如何处理Set-Cookie头部无关。 - Martijn Pieters
2
那个时候,得票数为-3的答案解决了我的问题。我设置了Secure=true,但忘记了在本地主机上只使用http进行测试。这是新手错误。在Flask中使用secure=request.is_secure - Eloff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接