了解 Cookie

Cookie 是一小段数据,网站将其存储在用户的浏览器中,用于持久保存状态以及网站执行其功能所需的其他信息。

Cookie 是网站存储在其用户机器上的一个小文件,它存储的信息在浏览器和网站之间来回传递。

每个 Cookie 都是一个键值对,以及一些属性,这些属性控制何时以及在何处使用该 Cookie。这些属性用于设置过期日期或指示 Cookie 只能通过 HTTPS 发送等。您可以在 HTTP 标头或通过 JavaScript 接口设置 Cookie。

Cookie 是为网站添加持久状态的可用方法之一。多年来,它们的功能不断增长和发展,但也给平台留下了一些有问题的遗留问题。为了解决这个问题,浏览器(包括 Chrome、Firefox 和 Edge)正在改变其行为,以强制执行更注重隐私保护的默认设置。

Cookie 的实际应用

假设您有一个博客,您想向用户展示“最新动态”促销信息。用户可以关闭促销信息,然后在一段时间内不会再次看到它。您可以将该首选项存储在 Cookie 中,将其设置为在一个月(2,600,000 秒)后过期,并且仅通过 HTTPS 发送。标头如下所示:

Set-Cookie: promo_shown=1; Max-Age=2600000; Secure
Three cookies being sent to a browser from a server in a response
服务器使用 Set-Cookie 标头设置 Cookie。

当您的读者查看满足这些要求的页面(他们使用安全连接,并且 Cookie 不到一个月)时,他们的浏览器将在其请求中发送此标头:

Cookie: promo_shown=1
Three cookies being sent from a browser to a server in a request
您的浏览器在 Cookie 标头中发回 Cookie。

您还可以使用 JavaScript 中的 document.cookie 添加和读取该站点可用的 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"
JavaScript accessing cookies within the browser
JavaScript 可以使用 document.cookie 访问 Cookie。

如果您在一些热门网站上尝试此操作,您会注意到它们中的大多数设置的 Cookie 远远不止三个。在大多数情况下,这些 Cookie 会在对该域的每个请求上发送,这会产生许多影响。对于您的用户来说,上传带宽通常比下载带宽更受限制,因此所有出站请求的开销都会增加首次字节到达时间的延迟。请保守设置 Cookie 的数量和大小。利用 Max-Age 属性来帮助确保 Cookie 不会停留的时间超过需要的时间。

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

如果您回到您之前查看的相同站点选择,您可能会注意到存在各种域的 Cookie,而不仅仅是您当前正在访问的域。与当前站点域匹配的 Cookie(即浏览器地址栏中显示的内容)称为第一方 Cookie。同样,来自当前站点以外域的 Cookie 称为第三方 Cookie。这不是绝对标签,而是相对于用户的上下文而言的;相同的 Cookie 可以是第一方 Cookie 或第三方 Cookie,具体取决于用户当时所在的站点。

Three cookies being sent to a browser from different requests on the same page
Cookie 可能来自一个页面上的各种不同域。

继续前面的示例,假设您的某篇博文包含一张特别棒的猫的照片,并且托管在 /blog/img/amazing-cat.png。由于它是一张非常棒的图片,另一个人直接在其网站上使用了它。如果访问者访问过您的博客并且具有 promo_shown Cookie,那么当他们在另一个人的网站上查看 amazing-cat.png 时,该 Cookie 将被发送到该图片请求中。这对任何人都没有特别的用处,因为 promo_shown 在这个人的网站上没有任何用途,它只是增加了请求的开销。

如果这是一个意外的效果,那么您为什么要这样做呢?正是这种机制允许站点在第三方上下文中使用时保持状态。例如,如果您在您的网站上嵌入了一个 YouTube 视频,那么访问者将在播放器中看到“稍后观看”选项。如果您的访问者已经登录到 YouTube,则该会话通过第三方 Cookie 在嵌入式播放器中可用 - 这意味着“稍后观看”按钮将直接保存视频,而无需提示他们登录或必须将他们从您的页面导航到 YouTube 再返回。

The same cookie being sent in three different contexts
在访问不同页面时,会发送第三方上下文中的 Cookie。

Web 的文化属性之一是它倾向于默认开放。这在一定程度上使得如此多的人能够在那里创建自己的内容和应用程序。然而,这也带来了一些安全和隐私问题。跨站请求伪造 (CSRF) 攻击依赖于 Cookie 附加到对给定来源的任何请求这一事实,无论谁发起该请求。例如,如果您访问 evil.example,那么它可以触发对 your-blog.example 的请求,并且您的浏览器会愉快地附加关联的 Cookie。如果您的博客在验证这些请求时不够仔细,那么 evil.example 可能会触发删除帖子或添加他们自己的内容等操作。

用户也越来越意识到 Cookie 如何用于跟踪他们在多个网站上的活动。然而,到目前为止,还没有办法明确声明您对 Cookie 的意图。您的 promo_shown Cookie 应该只在第一方上下文中发送,而旨在嵌入到其他网站上的小部件的会话 Cookie 则有意用于在第三方上下文中提供登录状态。

您可以通过设置适当的 SameSite 属性 来明确声明您对 Cookie 的意图。

要识别您的第一方 Cookie 并设置适当的属性,请查看第一方 Cookie 食谱