ookies是可用于向网站添加持久状态的方法之一。多年来,他们的能力不断发展壮大,但使平台遗留了一些有问题的遗留问题。为了解决这个问题,浏览器(包括Chrome,Firefox和Edge)正在更改其行为,以强制实施更多保留隐私的默认设置。
每个cookie是一个“ 键=值”对以及一些控制何时和何处使用该cookie的属性。您可能已经使用这些属性来设置诸如到期日期之类的信息,或者指示cookie仅应通过HTTPS发送。服务器通过在响应中发送适当命名的Set-Cookie标头来设置cookie。有关所有详细信息,您可以深入研究RFC6265bis,但现在这里是快速更新。
假设您有一个博客,希望在其中向用户显示“新功能”促销。用户可以撤消该促销,然后过一会儿再看不到它。您可以将该首选项存储在cookie中,将其设置为在一个月(2,600,000秒)内到期,然后仅通过HTTPS发送。该标题看起来像这样:
Set-Cookie: promo_shown=1; Max-Age=2600000; Secure
当您的读者查看满足那些要求的页面时,即他们处于安全连接并且cookie不到一个月,那么他们的浏览器将在其请求中发送此标头:
Cookie: promo_shown=1
您还可以使用document.cookie在JavaScript中添加和读取可用于该站点的cookie。对document.cookie进行分配将使用该密钥创建或覆盖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"
如果您在一些受欢迎的站点上尝试此操作,您会注意到大多数站点设置的数量远远超过了三个cookie。在大多数情况下,这些cookie是在每个单个请求上发送到该域的,这有很多含义。对于您的用户,上传带宽通常比下载带宽受到更多限制,因此所有出站请求的开销都会增加您的第一个字节的时间延迟。保守您设置的Cookie的数量和大小。利用“最大年龄”(Max-Age)属性可帮助确保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。
网络的文化属性之一是默认情况下它倾向于打开。这是让如此多的人在那里创建自己的内容和应用程序的一部分。但是,这也带来了许多安全和隐私问题。跨站点请求伪造(CSRF)攻击依赖于将Cookie附加到给定源的任何请求这一事实,无论谁发起该请求。例如,如果您访问evil.example,则它可以触发对your-blog.example的请求,并且您的浏览器会很高兴地附加关联的cookie。如果您的博客对如何验证这些请求不满意,那么evil.example可能会触发删除帖子或添加自己的内容之类的操作。
用户也越来越意识到如何使用cookie来跟踪他们跨多个站点的活动。但是,到目前为止,还没有一种方法可以明确地表示您对Cookie的意图。您的promo_shown Cookie仅应在第一方上下文中发送,而故意嵌入到其他站点的窗口小部件的会话cookie则有意在第三方上下文中提供登录状态。
通过SameSite属性显式说明Cookie的使用情况
#SameSite属性(在RFC6265bis中定义)的引入使您可以声明将cookie限制在第一方上下文还是在同一站点上下文中。准确了解“站点”在这里的含义是有帮助的。该站点是域后缀和域后缀的组合。例如,www.example.com域是示例站点的一部分。
`Key Term:
If the user is on your-project.github.io and requests an image from my-project.github.io that's a cross-site request.
`
在Cookie上引入SameSite属性可提供三种不同的方式来控制此行为。您可以选择不指定属性,也可以使用“严格”或“宽松”将cookie限制为同一站点请求。
如果将SameSite设置为Strict,则cookie仅在第一方上下文中发送。用用户术语讲,只有在Cookie的站点与浏览器的URL栏中当前显示的站点匹配时,才会发送cookie。因此,如果按如下所示设置 promo_shown cookie:
Set-Cookie:promo_shown = 1;SameSite =严格
当用户在您的网站上时,该Cookie将与预期的请求一起发送。但是,当您链接到您网站的链接时,例如从另一个网站或通过朋友发送的电子邮件,在该初始请求中,将不会发送cookie。当您有与功能相关的cookie总是处于初始导航之后(例如更改密码或购买商品),但对promo_shown的限制过于严格时,这很好。如果您的读者访问该站点的链接,则他们希望发送Cookie,以便可以应用其首选项。
那就是SameSite = Lax的出现,它允许通过这些顶级导航发送cookie。让我们从上面重新访问cat文章示例,其中另一个站点引用了您的内容。他们直接利用您的猫照片,并提供指向您原始文章的链接。
看看这只神奇的猫!
阅读文章。
Cookie已设置为:
套餐Cookie:promo_shown = 1;SameSite =松懈
当读者在其他人的博客上时,如果浏览器请求amazing-cat.png,则不会发送该cookie。但是,当读者通过链接访问您博客上的cat.html时,该请求将包含cookie。这使得Lax成为影响网站显示的Cookie的不错选择,而Strict对于与您的用户执行的操作相关的Cookie很有用。
严格和宽松都不是您网站安全的完整解决方案。Cookie是作为用户请求的一部分发送的,您应该将它们与其他任何用户输入一样对待。这意味着对输入进行消毒和验证。切勿使用cookie来存储您认为是服务器端机密的数据。
最后,可以选择不指定值,该值以前是隐式声明您希望在所有上下文中发送cookie的方式。在RFC6265bis的最新草案中,通过引入SameSite = None的新值来明确指出这一点。这意味着您可以使用“无”来明确表示您有意要在第三方上下文中发送cookie。
在没有SameSite的情况下更改为默认行为
尽管SameSite属性得到了广泛支持,但不幸的是,它尚未被开发人员广泛采用。开放的默认发送Cookie到处意味着所有用例都可以使用,但使用户容易受到CSRF和意外信息泄漏的影响。为了鼓励开发人员陈述其意图并为用户提供更安全的体验,IETF提案《渐进式更好的Cookies》提出了两个关键更改:
没有SameSite属性的Cookie将被视为SameSite = Lax。
SameSite = None的Cookie也必须指定安全,这意味着它们需要安全的上下文。
Chrome自80版本起就实现了这些行为。Firefox从Firefox 69起就可以对其进行测试,并将在将来使它们成为默认行为。要在Firefox中测试这些行为,请打开about:config并设置network.cookie.sameSite.laxByDefault。Edge还计划更改其默认行为。