A cookie associated with a cross-site resource at <URL> was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at <URL> and <URL>.

Cookies是可用于向网站添加持久状态的方法之一。多年来,他们的能力不断发展和壮大,但遗留了一些有问题的遗留问题。为了解决这个问题,浏览器(包括Chrome,Firefox和Edge)正在更改其行为,以强制实施更多保留隐私的默认设置。

每个cookie是一个key=value对以及一些控制何时和何处使用该cookie的属性。您可能已经使用这些属性来设置诸如到期日期之类的信息,或者指示cookie仅应通过HTTPS发送。服务器通过在响应中发送适当命名的Set-Cookie标头来设置cookie。有关所有详细信息,您可以深入研究RFC6265bis,但现在这里是快速更新。

假设您有一个博客,希望在其中向用户显示“新功能”促销。用户可以撤消该促销,然后过一会儿再看不到它。您可以将该首选项存储在cookie中,将其设置为在一个月(2,600,000秒)内到期,然后仅通过HTTPS发送。该标题看起来像这样:

Set-Cookie: promo_shown=1; Max-Age=2600000; Secure
服务器使用Set-Cookie标头设置cookie

服务器使用Set-Cookie标头设置cookie

当您的读者查看满足这些要求的页面时,即他们处于安全连接并且Cookie的使用期限不到一个月,那么他们的浏览器就会在其请求中发送此标头:

Cookie: promo_shown=1
您的浏览器将Cookie发送回Cookie标头中

您的浏览器将Cookie发送回Cookie标头中

您还可以使用document.cookie在JavaScript中添加和读取可用于该站点的cookie。 对document.cookie进行分配将使用key创建或覆盖cookie。 例如,您可以在浏览器的JavaScript控制台中尝试以下操作:

> document.cookie = "promo_shown=1; Max-Age=2600000; Secure"
< "promo_shown=1; Max-Age=2600000; Secure"

读取document.cookie将输出在当前上下文中可访问的所有cookie,每个cookie用分号分隔:

> document.cookie;
< "promo_shown=1; color_theme=peachpuff; sidebar_loc=left"
JavaScript可以使用document.cookie访问cookie

JavaScript可以使用document.cookie访问cookie

如果您在一些受欢迎的站点上尝试此操作,您会注意到大多数站点设置的数量远远超过了三个cookie。 在大多数情况下,这些cookie是在每个单个请求上发送到该域的,这有很多含义。对于您的用户,上传带宽通常比下载带宽受到更多限制,因此所有出站请求的开销都会增加您的第一个字节的时间延迟。 保守您设置的Cookie的数量和大小。利用Max-Age属性可帮助确保cookie的停留时间不会超过所需的时间。

什么是第一方和第三方Cookie?

您可能会注意到存在针对各种域的cookie,而不仅仅是您当前正在访问的cookie。 与当前网站的域匹配的Cookie(即浏览器地址栏中显示的Cookie)称为第一方Cookie。 同样,来自当前站点以外的域的cookie也称为第三方cookie。 这不是绝对的标签,而是相对于用户的上下文。 同一Cookie可以是第一方也可以是第三方,这取决于用户当时所在的网站。

Cookie可能来自一页上的各种不同域

Cookie可能来自一页上的各种不同域

假设您的一篇博客文章中包含一张特别令人惊叹的猫的图片,并将其托管在/blog/img/amazing-cat.png。因为这是一个了不起的图像,所以另一个人直接在他们的网站上使用它。如果访问者访问过您的博客并具有promo_shown cookie,那么当他们在其他人的站点上查看amazing-cat.png时,将在该图像请求中发送cookie。这对任何人都不是特别有用,因为promo_shown并未用于此人网站上的任何内容,它只是增加了请求的开销。

如果那是意想不到的效果,那么为什么要这样做呢?通过这种机制,站点可以在第三方上下文中使用时保持状态。例如,如果您在自己的网站上嵌入YouTube视频,则访问者将在播放器中看到“稍后观看”选项。如果您的访问者已经登录YouTube,则该会话将通过第三方Cookie在嵌入式播放器中提供-意味着“稍后观看”按钮将立即保存视频,而不是提示他们登录或必须将它们从您的页面上移开,然后返回到YouTube。

当访问不同页面时,将发送第三方上下文中的cookie

当访问不同页面时,将发送第三方上下文中的cookie

网络的文化属性之一是默认情况下它倾向于打开。这是让如此多的人在那里创建自己的内容和应用程序的一部分。但是,这也带来了许多安全和隐私问题。跨站点请求伪造(CSRF)攻击依赖于将Cookie附加到给定源的任何请求这一事实,无论谁发起该请求。例如,如果您访问evil.example,则它可以触发对your-blog.example的请求,并且您的浏览器会很高兴地附加关联的cookie。如果您的博客对如何验证这些请求不谨慎,那么evil.example可能会触发删除帖子或添加自己的内容之类的操作。

用户也越来越意识到如何使用cookie来跟踪他们跨多个站点的活动。但是,到目前为止,还没有一种方法可以明确地表示您对Cookie的意图。您的promo_shown Cookie仅应在第一方上下文中发送,而故意嵌入到其他站点的窗口小部件的会话cookie则有意在第三方上下文中提供登录状态。

将Cookie的上下文明确标记为None,Lax或Strict

将Cookie的上下文明确标记为None,Lax或Strict

如果您提供其他站点使用的服务,例如小部件,嵌入式内容,会员计划,广告或跨多个站点登录,则应使用None以确保您的意图明确。

使用SameSite属性明确声明Cookie的使用情况

SameSite属性(在RFC6265bis中定义)的引入使您可以声明cookie是否应限于第一方或同一站点上下文。 准确了解“站点”在这里的含义是有帮助的。 该站点是域后缀和域后缀的组合。 例如,www.web.dev域是web.dev站点的一部分。

如果用户位于www.web.dev上,并从static.web.dev请求图像,则该图像是同一站点的请求。

公共后缀列表对此进行了定义,因此它不仅是.com之类的顶级域名,还包括github.io之类的服务。 这使your-project.github.io和my-project.github.io可以算作单独的站点。

如果用户在your-project.github.io上,并从my-project.github.io请求图像,则这是跨站点请求。

在Cookie上引入SameSite属性可提供三种不同的方式来控制此行为。 您可以选择不指定属性,也可以使用StrictLax将cookie限制为同一站点请求。

如果将SameSite设置为Strict,则cookie仅在第一方上下文中发送。 用用户术语讲,只有在Cookie的站点与浏览器的URL栏中当前显示的站点匹配时,才会发送cookie。 因此,如果将promo_shown cookie设置如下:

Set-Cookie: promo_shown=1; SameSite=Strict

当用户在您的网站上时,该Cookie将与预期的请求一起发送。 但是,当跟随一个链接到您网站的链接时,例如从另一个网站或通过朋友发送的电子邮件,在该初始请求中,将不会发送cookie。 当您有与功能相关的cookie总是处于初始导航之后(例如更改密码或购买商品),但对promo_shown的限制过于严格时,这很好。 如果您的读者访问该站点的链接,则他们希望发送Cookie,以便可以应用其首选项。

SameSite=Lax的出现,它允许通过这些顶级导航发送cookie。 让我们从上面重新访问cat文章示例,其中另一个站点引用了您的内容。 他们直接利用您的猫照片,并提供指向您原始文章的链接。

<p>Look at this amazing cat!</p>
<img src="https://blog.example/blog/img/amazing-cat.png" />
<p>Read the <a href="https://blog.example/blog/cat.html">article</a>.</p>

Cookie已设置为:

Set-Cookie: promo_shown=1; SameSite=Lax

当读者在其他人的博客上时,如果浏览器请求amazing-cat.png,则不会发送该cookie。 但是,当读者通过链接访问您博客上的cat.html时,该请求将包含cookie。 这使得Lax成为影响网站显示的Cookie的不错选择,而Strict对于与您的用户执行的操作相关的Cookie很有用。

Strict和Lax都不是您网站安全的完整解决方案。Cookie是作为用户请求的一部分发送的,您应该将它们与其他任何用户输入一样对待。 这意味着对输入进行消毒和验证。 切勿使用cookie来存储您认为是服务器端机密的数据。

最后,可以选择不指定值,该值以前是隐式声明您希望在所有上下文中发送cookie的方式。 在RFC6265bis的最新草案中,通过引入SameSite=None的新值来明确指出这一点。 这意味着您可以使用“无”来明确表示您有意要在第三方上下文中发送cookie。

在没有SameSite的情况下更改默认行为

尽管SameSite属性得到了广泛支持,但不幸的是,它尚未被开发人员广泛采用。 开放的默认发送Cookie到处意味着所有用例都可以使用,但使用户容易受到CSRF和意外信息泄漏的影响。 为了鼓励开发人员陈述其意图并为用户提供更安全的体验,IETF提案《Incrementally Better Cookies》提出了两个关键更改:

  • 没有SameSite属性的Cookie将被视为SameSite=Lax
  • SameSite=None的Cookie也必须指定Secure,这意味着它们需要安全的上下文。

Chrome自80版本起就实现了这些行为。Firefox从Firefox 69起就可以对其进行测试,并将在将来使它们成为默认行为。 要在Firefox中测试这些行为,请打开about:config并设置network.cookie.sameSite.laxByDefaultEdge也在计划更改其默认行为。

注意

默认SameSite=Lax

未设置属性

Set-Cookie: promo_shown=1

如果发送未指定任何SameSite属性的Cookie,则应用默认行为

Set-Cookie: promo_shown=1; SameSite=Lax

浏览器将将该cookie视为已指定SameSite=Lax

虽然这是为了应用更安全的默认值,但理想情况下,您应该设置一个明确的SameSite属性,而不要依赖浏览器为您应用该属性。 这使您对Cookie的意图明确,并提高了跨浏览器获得一致体验的机会。

与默认的SameSite=Lax相比,Chrome所应用的默认行为要宽松一些,因为它将允许某些Cookie在顶级POST请求上发送。 您可以在the blink-dev announcement中看到确切的详细信息。 这只是暂时的缓解措施,您仍应修复跨站点Cookie以使用SameSite=None; Secure

SameSite=None必须加上secure

Set-Cookie: widget_session=abc123; SameSite=None

设置没有Secure的cookie将被拒绝

Set-Cookie: widget_session=abc123; SameSite=None; Secure

您必须确保将SameSite=None与Secure属性同时使用

您可以通过启用chrome://flags/#cookies-without-same-site-must-be-secure来测试从Chrome 76开始的此行为和通过about.config从Firefox 69中测试该行为,方法是设置network.cookie.sameSite.noneRequiresSecure

您将需要在设置新的Cookie时应用此功能,并主动刷新现有的Cookie,即使这些Cookie的有效期限未到。

如果您依赖于在您的站点上提供第三方内容的任何服务,则还应该向提供商咨询他们正在更新其服务。 您可能需要更新依赖项或代码片段,以确保您的网站采用了新的行为。

这两个更改都与已正确实现SameSite属性的先前版本或根本不支持它的浏览器向后兼容。 通过将这些更改应用于Cookie,您可以明确指定其预期用途,而不是依赖浏览器的默认行为。 同样,任何尚未识别SameSite=None的客户端都应忽略它,并像未设置属性一样继续操作。

许多旧版本的浏览器(包括Chrome,Safari和UC浏览器)与新的None属性不兼容,并且可能会忽略或限制Cookie。 此行为在当前版本中已修复,但是您应该检查流量以确定受影响的用户比例。 您可以在查询list of known incompatible clients on the Chromium site

SameSite cookie recipes

有关准确更新Cookie的详细信息,以成功处理对SameSite=None的这些更改以及浏览器行为的差异,请转到后续文章SameSite cookie 指南

SameSite cookies explained