主题
字号
CHAPTER 04 ≈ 30 MIN READ

Cookies、存储与登录态

4.1 一个你每天都在经历的场景

4.1.1 为什么你不需要每次都登录

打开手机,点开淘宝——你直接就进去了,不需要输密码。打开 B 站——你的头像在右上角,推荐页是你的口味。打开微博——你的关注列表就在那里。

你有没有想过:这些网站是怎么记住你的?

你可能觉得这是理所当然的事。但从技术角度看,这其实很不自然。因为 HTTP 协议——也就是浏览器和服务器之间通信的规则——有一个根本特性:无状态

4.1.2 什么叫"无状态"

"无状态"的意思是:服务器不会记住你是谁。你发的每一个请求,对服务器来说都是全新的、陌生的。

想象一个极端的场景:你去一家咖啡店,点了一杯拿铁。店员做好了递给你。你说"再加一块蛋糕"。店员一脸茫然地看着你:"你是谁?你要什么?"——因为他完全不记得 30 秒前刚给你做过咖啡。

这就是 HTTP 的工作方式。你点击"加入购物车",服务器处理了。你点击"去结算",服务器问:"购物车?什么购物车?你是谁?"

4.1.3 为什么要设计成无状态

这听起来很蠢,但其实是故意的。HTTP 设计成无状态有一个很实际的原因:可扩展性

淘宝有几亿用户。如果服务器要记住每一个用户的状态(谁登录了、谁的购物车里有什么、谁在看哪个页面),那服务器的内存会爆炸。而且淘宝不是一台服务器,是几万台——你的第一个请求可能被服务器 A 处理,第二个请求被服务器 B 处理。如果状态存在服务器 A 上,服务器 B 就不认识你了。

无状态意味着:每个请求都是独立的,任何一台服务器都能处理,不需要知道"之前发生了什么"。这让系统可以轻松地加机器、做负载均衡。

但用户体验不能是无状态的。所以需要一个机制,让浏览器在每次请求时"自报家门"——告诉服务器"我是谁、我之前做了什么"。

这个机制就是 Cookie

4.2 Cookie:互联网的"记忆"

Cookie 就是一小段文本,存在你的浏览器里。它的唯一作用是:告诉服务器"我是谁"

注意:Cookie 本身不包含你的数据(不存你的收藏列表、不存你的密码、不存你的个人信息)。它只是一个编号——就像酒店房卡上的房间号。

你刷房卡,前台看到"302",然后去电脑系统里查:302 住的是 Mav,入住日期是 5/18。房卡本身不包含你的信息,真正的信息在酒店的电脑系统(服务器的数据库)里。

所以完整的流程是:

  1. 你带着 Cookie 访问网站("我是 sess_abc123")
  2. 服务器验证这个 Cookie:这个 ID 是我签发的吗?还没过期吗?
  3. 验证通过 → 服务器在自己的数据库里查找对应的用户信息
  4. 服务器处理你的请求(显示你的收藏、处理你的订单等)

伪造一个假 Cookie 是没用的——服务器那边没有对应的记录,验证不通过。

4.2.2 一个完整的例子

场景:你登录 bilibili.com,然后点收藏

第一步:登录

浏览器 ──── POST /login {user: "mav", pass: "***"} ────▶ B站服务器
                                                          │
                                                          │ 验证密码通过!
                                                          │ 在数据库里记录:
                                                          │   "sess_7f3a" → 用户 mav
                                                          ▼
浏览器 ◀─── 200 OK                                    ── B站服务器
             Set-Cookie: session=sess_7f3a; HttpOnly
             
             (服务器说:"以后带着这个编号来找我")
第二步:点击收藏某个视频

浏览器 ──── POST /favorite?video=BV1xx                ────▶ B站服务器
             Cookie: session=sess_7f3a                       │
             (浏览器自动带上 Cookie)                         │
                                                              │ 1. 验证 sess_7f3a → 是 mav
                                                              │ 2. 在数据库里写入:
                                                              │    mav 收藏了 BV1xx
                                                              ▼
浏览器 ◀─── 200 OK(收藏成功)                         ── B站服务器

关键点:收藏数据存在服务器的数据库里,不是存在 Cookie 里。Cookie 只是让服务器知道"这个请求来自 mav"。

Cookie 是 1994 年由 Netscape 的工程师 Lou Montulli(当时 23 岁)发明的。

他面临的问题很具体:Netscape 的在线商店需要购物车功能,但 HTTP 无状态让服务器记不住"谁的购物车里有什么"。

Montulli 考虑过一个更简单的方案:给每个浏览器一个出厂自带的固定编号,所有网站都能读取。这样任何网站都能通过这个编号认出你。

但他意识到这有严重的隐私问题。想象一下:

如果这些网站互相交换数据,它们就能拼出你的完整画像:"browser_001 在淘宝买了什么、看了什么新闻、搜索了什么病症"。一个 ID 走天下 = 全网裸奔。

所以 Montulli 设计了 Cookie 的核心规则:每个网站给你的 ID 是独立的、互相不可见的

两个网站无法通过 Cookie 串联你的行为。这就是 Cookie 的"同源策略"——每个 Cookie 只属于设置它的那个域名。

(当然后来广告商用"第三方 Cookie"打破了这个隔离,但那是后话。)

打开任意网站,按 F12 → Application(Chrome)或 Storage(Firefox)→ Cookies,你能看到一个表格。一个典型的 Cookie 长这样:

Set-Cookie: session=abc123; Domain=bilibili.com; Path=/; Max-Age=2592000; Secure; HttpOnly; SameSite=Lax
部分 含义
session=abc123 名字和值(就是那个"编号")
Domain=bilibili.com 只属于这个网站
Path=/ 网站所有页面都带上
Max-Age=2592000 有效期 30 天(单位是秒)
Secure 只在 HTTPS 加密连接中发送
HttpOnly JavaScript 读不到(防止被恶意脚本偷走)
SameSite=Lax 限制跨站请求时是否携带

4.3.2 有效期:为什么有些网站要重新登录

所有 Cookie 都有有效期。但"到期"不等于"马上要重新登录"。你日常的体验差异来自三个因素:

1. 有效期设多长

网站类型 典型有效期 原因
银行/支付 几分钟~几小时 安全要求极高
DigitalOcean 等云服务 几小时~几天 涉及服务器操作和付费
GitHub、B站 30 天~1 年 社交/工具类,安全要求相对低

2. 会不会自动续期

GitHub 的策略是:Cookie 有效期 30 天,但每次你访问时都会刷新这个倒计时。相当于每次刷房卡都把有效期延长 30 天。只要你不连续 30 天不上 GitHub,就永远不会过期。

DigitalOcean 的策略是:Cookie 有效期到了就是到了,不续期。到期必须重新登录。

3. 服务器端是否主动失效

即使你的 Cookie 还没过期,服务器也可以主动让它失效。比如:

Cookie 分两种:

Session Cookie:没有设置 Max-AgeExpires。关闭浏览器就消失。适合"这次用完就算了"的场景。

Persistent Cookie:设置了有效期。关闭浏览器再打开还在。适合"记住我"的场景。

你在登录页面看到的"记住我"复选框,本质就是:

4.3.4 动手看看

打开浏览器控制台(F12 → Console),试试:

// 设置一个 Cookie(有效期 60 秒)
document.cookie = "my_test=hello; max-age=60; path=/";

// 读取当前页面所有 Cookie
console.log(document.cookie);

// 60 秒后 my_test 会自动消失
// 手动删除:
document.cookie = "my_test=; max-age=0; path=/";

注意:标记了 HttpOnly 的 Cookie 你用 JavaScript 读不到。这是故意的——防止恶意脚本偷走你的登录凭证。

4.4 登录是怎么实现的

4.4.1 两种思路

登录的本质问题是:第一次验证了密码之后,后续请求怎么证明"我还是刚才那个人"?

有两种完全不同的思路:

思路一:服务器记住你(Session)

类比:你去图书馆办了借书证。图书馆在自己的系统里记录了"借书证 #302 = 张三"。你每次来借书,出示借书证,图书馆查系统确认你是张三。

思路二:你自己带着证明(JWT)

类比:你去公证处做了一份公证书,上面写着"张三,身份证号 xxx,2026 年 5 月 18 日公证",盖了公证处的章。之后你去任何地方办事,直接出示这份公证书。对方验证公章是真的 → 信任上面写的内容。不需要打电话给公证处确认。

4.4.2 Session:服务器记住你

这是最传统的方式:

1. 你输入密码,服务器验证通过
2. 服务器在自己的内存/数据库里创建一条记录:
     "sess_abc123" → {用户: mav, 登录时间: 10:00}
3. 服务器把这个 ID 通过 Cookie 发给你:
     Set-Cookie: sid=sess_abc123
4. 之后你每次请求都带着这个 Cookie
5. 服务器收到后,拿着 "sess_abc123" 去查自己的记录
6. 查到了 → 你是 mav → 处理请求
   查不到 → 你没登录或已过期 → 拒绝

优点

缺点

4.4.3 JWT:你自己带着"公证书"

JWT(JSON Web Token)的思路完全不同:服务器不存任何东西,把你的身份信息直接写在 Token 里,用签名防篡改,让你自己带着走

一个 JWT 长这样:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoibWF2IiwiZXhwIjoxNzE2MDAwMDAwfQ.xxxxx

看起来像乱码,但其实是三段用 . 分隔的 Base64 编码(不是加密,只是换了一种写法,任何人都能解码看到原文)。解码后:

第一段(Header):  {"alg": "HS256"}
  → 用什么签名算法

第二段(Payload): {"user": "mav", "exp": 1716000000}
  → 原文:你是谁、什么时候过期

第三段(Signature): HMAC-SHA256(第一段 + 第二段, 服务器密钥)
  → 服务器用密钥对原文做的签名

核心安全逻辑tips

服务器登录验证通过后,做了两件事:

  1. 把你的信息写成原文(Payload)
  2. 用自己的密钥对原文做签名(Signature)

然后把原文 + 签名一起给你。

你拿着这个 JWT,能看到原文("我是 mav,有效期到明天"),你甚至可以手动把有效期从 30 天改成 60 天。但是你改不了签名——因为签名是用服务器的密钥算出来的,你没有那个密钥。

服务器收到你的 JWT 后怎么验证?很简单:

  1. 取出你带来的原文
  2. 用自己的密钥重新算一遍签名
  3. 对比算出来的签名 vs 你带来的签名
  4. 一样 → 原文没被篡改 → 信任内容
  5. 不一样 → 有人改过原文 → 拒绝

这就是为什么服务器不需要存任何东西:它不需要记住"我给谁发过什么 Token"。它只需要有自己的密钥,就能随时验证任何 Token 是不是自己签发的、有没有被篡改过。就像公证处不需要记住每一份公证书的内容——只要验证公章是真的,就能信任上面写的内容。

优点

缺点

4.4.4 你日常遇到的登录方式

场景 背后的技术 为什么
网站登录后关浏览器还在 Persistent Cookie + Session Cookie 有效期长 + 自动续期
"记住我"复选框 控制 Cookie 有效期 勾选 = 30 天,不勾选 = 关浏览器就没
手机 App 一直不用重新登录 JWT 存在 App 本地 有效期设很长(几个月)
银行 5 分钟不操作就要重新登录 Session 超时极短 安全要求高
"在其他设备上登出" 服务器删除 Session 或者把 JWT 加入黑名单
扫码登录 手机确认后服务器给 PC 发 Token 手机已经验证了身份

4.5 第三方 Cookie:从工具到武器

4.5.1 第一方 vs 第三方

这是理解 Cookie 隐私问题的关键概念:

第一方 Cookie:你正在访问的网站设置的。比如你在 bilibili.com 上,bilibili.com 给你设了一个 Cookie。合理、必要、无害。

第三方 Cookie:你正在访问的网站之外的域名设置的。比如你在 news.com 上看新闻,但页面里嵌入了 ads.google.com 的广告代码,这个广告代码偷偷给你设了一个 Cookie,域名是 google.com

为什么第三方 Cookie 能存在?因为一个网页可以加载来自任何域名的资源——图片、脚本、iframe。每加载一个外部资源,那个外部域名就有机会设置 Cookie。

4.5.2 跨站追踪:一个真实的场景

让我用一个具体的故事解释第三方 Cookie 是怎么追踪你的:

周一上午:你在 news.com 看新闻。页面底部有一个来自 tracker.com 的 1x1 像素透明图片(你根本看不见它)。tracker.com 的服务器给你设了一个 Cookie:user_id=X7K9P2

周一下午:你在 shopping.com 逛商品。这个网站也嵌入了 tracker.com 的代码。你的浏览器访问 tracker.com 时自动带上了 Cookie user_id=X7K9P2。现在 tracker.com 知道了:X7K9P2 这个人上午看新闻,下午在逛购物网站。

周二:你在 travel.com 搜机票。同样的 tracker.com 代码。现在它知道你可能要出差或旅行。

一周后:你在各种网站上开始看到机票广告和旅行箱广告。

这不是假设——这就是 Google、Facebook、以及无数广告网络每天在做的事情。Google 的广告代码(Google Analytics、Google Ads)嵌入在互联网上超过 80% 的网站中。这意味着 Google 几乎能追踪你访问的每一个网站。

4.5.3 为什么你搜了什么就看到什么广告

现在你理解了:

  1. 你在 A 网站搜索"跑步鞋"
  2. A 网站嵌入了广告网络的代码,广告网络通过第三方 Cookie 知道你搜了"跑步鞋"
  3. 你去 B 网站(一个完全不相关的新闻网站)
  4. B 网站也嵌入了同一个广告网络的代码
  5. 广告网络识别出你(通过第三方 Cookie),知道你对跑步鞋感兴趣
  6. 给你展示跑步鞋广告

这就是所谓的"精准广告"或"定向广告"。它的基础设施就是第三方 Cookie。

4.5.4 各浏览器的态度

浏览器 对第三方 Cookie 的态度 时间
Safari 默认阻止 2017 年起
Firefox 默认阻止 2019 年起
Brave 从诞生起就阻止 2016 年起
Chrome 保留不动 至今

Chrome 的故事值得单独讲:

六年的"即将废弃",最终结果是:什么都没变。

为什么?因为 Google 2024 年的广告收入超过 2600 亿美元,占总收入的 77%。第三方 Cookie 是这个广告帝国的基础设施。废弃它等于自断财路。

这就是为什么浏览器选择很重要:如果你用 Chrome,你的浏览行为正在被第三方 Cookie 追踪;如果你用 Safari、Firefox 或 Brave,这种追踪默认就被阻止了。同一个人,同一个网站,不同的浏览器,隐私保护天差地别。

4.6.1 法律要求

那些"Accept Cookies"弹窗来自欧盟的法律:

ePrivacy 指令(2009 年修订):在用户设备上存储信息(包括 Cookie)之前,必须获得用户同意。

GDPR(2018 年生效):定义了什么算"有效同意"——必须是自由的、明确的、可撤回的。

简单说:网站想在你浏览器里存 Cookie(除了网站正常运行必需的),必须先问你。不问就存 = 违法 = 罚款。

罚款有多狠?截至 2026 年 5 月,欧盟累计开出了超过 106 亿欧元的 GDPR 罚款。2025 年 9 月,法国 CNIL 单独对 Google 罚了 3.25 亿欧元——因为 Gmail 里未经同意展示广告。tips

法律把 Cookie 分成几类:

类别 需要同意? 例子
严格必要 不需要 登录状态、购物车、安全验证
功能性 需要 语言偏好、字体大小、深色模式
分析统计 需要 Google Analytics、访问量统计
广告追踪 需要 第三方广告 Cookie、行为画像

"严格必要"的 Cookie 不需要同意——因为没有它们网站就没法用(比如你登录后的 session Cookie)。但其他所有类型都需要你明确点"同意"才能设置。

4.6.3 暗黑模式:为什么"拒绝"这么难

你有没有注意到,大多数 Cookie 弹窗的设计都在诱导你点"接受全部":

这种设计叫 Dark Patterns(暗黑模式)——故意让"对用户有利的选择"变得困难,让"对公司有利的选择"变得容易。

2025 年,欧洲数据保护委员会(EDPB)发布了专门针对 Cookie 弹窗暗黑模式的执法指南。荷兰数据保护局在 2025 年 4 月一次性向 50 家公司发出警告。但执法速度远跟不上违规速度。

4.6.4 你应该怎么做

最简单的做法:直接点"拒绝全部"或"仅必要"。网站功能 99% 不受影响——你只是拒绝了被追踪,不是拒绝了使用网站。

更省事的做法:安装一个浏览器扩展自动帮你拒绝:

最彻底的做法:用 Safari / Firefox / Brave,它们默认就阻止了第三方 Cookie,很多追踪类 Cookie 根本不会被设置,弹窗问你也没意义。

但说实话,作为一个普通用户……

换浏览器对很多人来说不现实——Chrome 里的书签、密码、扩展、登录状态,迁移成本太高。装插件也有门槛,而且把隐私决策交给一个插件本身就有点讽刺(你怎么确定这个插件不收集你的数据?)。所以对大多数人来说,最实际的选择就是在弹窗出现时做决定。

你可能和很多人一样,一直点"接受全部"——因为怕"拒绝"会影响网站功能。实际上:完全可以放心点"拒绝全部"。你拒绝的只是追踪类和广告类 Cookie,网站正常运行需要的 Cookie(登录、购物车)属于"严格必要"类别,不需要你同意就会自动设置。拒绝后你能正常浏览、正常登录、正常购物,唯一的区别是广告商追踪不到你了。

另外你可能注意到:YouTube、GitHub、B 站这些大网站从来不弹 Cookie 弹窗。这不是因为它们不用 Cookie——它们用得很多。而是因为 Cookie 弹窗是欧盟法律要求的,这些网站要么判断你不在欧盟地区所以不弹,要么把同意条款藏在了注册时的用户协议里(你注册时点的那个"我同意"已经包含了 Cookie 授权)。所以不是它们不收集,只是不需要再单独问你。

4.7 除了 Cookie,浏览器还能存什么

Cookie 有一个硬伤:太小了(每个最多 4KB),而且每次请求都会被发送给服务器(浪费带宽)。所以现代浏览器提供了更多的存储方式。

4.7.1 LocalStorage:浏览器里的"记事本"

// 存数据(永久保存,除非手动清除)
localStorage.setItem('theme', 'dark');
localStorage.setItem('language', 'zh-CN');

// 读数据
const theme = localStorage.getItem('theme');  // "dark"

// 删数据
localStorage.removeItem('theme');

LocalStorage 的特点:

实际用途:你现在正在阅读的这个网站,深色模式的偏好、字号设置、阅读进度、便利贴内容——全部存在 LocalStorage 里。

4.7.2 SessionStorage:关了就没了

和 LocalStorage 几乎一样,唯一区别是:关闭标签页就清除

适合存"临时数据"——比如你在填一个很长的表单,中途不小心刷新了页面,SessionStorage 可以帮你恢复之前填的内容(只要你没关标签页)。

4.7.3 IndexedDB:浏览器里的数据库

对于更复杂的需求,浏览器提供了 IndexedDB——一个完整的客户端数据库,容量可以达到几百 MB 甚至 GB 级别。

实际用途

4.7.4 对比总结

Cookie LocalStorage SessionStorage IndexedDB
容量 4KB 5-10MB 5-10MB 数百 MB+
生命周期 可设置 永久 标签页关闭即清 永久
随请求发送
适用场景 身份认证 用户偏好 临时数据 离线应用

一句话总结:Cookie 是给服务器看的(身份认证),LocalStorage 是给浏览器自己用的(本地偏好),IndexedDB 是给复杂应用用的(离线数据库)。

4.8 无痕浏览:真的"无痕"吗

4.8.1 无痕模式做了什么

Chrome 叫"无痕模式"(Incognito),Safari 叫"无痕浏览"(Private Browsing),Firefox 叫"隐私浏览"(Private Window)。它们做的事情本质上一样:

开一个临时的、隔离的环境

但保留的东西

4.8.2 无痕模式防得了什么、防不了什么

能防 不能防
同一台电脑的其他人看到你的浏览记录 网站知道你的 IP 地址
网站通过 Cookie 追踪你(关窗口就没了) 公司/学校的网络管理员看到你访问了什么
上次搜索的内容影响这次的结果 浏览器指纹追踪(下一章讲)
自动登录(因为没有 Cookie) ISP(网络运营商)记录你的访问

一句话:无痕模式保护你不被本地追踪(同一台电脑的人看不到),但不保护你不被远程追踪(网站、网络管理员、运营商都能看到)。

4.8.3 什么时候该用无痕模式

4.8.4 一个常见误解

很多人以为无痕模式 = 匿名上网。不是的。Google 在 2024 年因为这个误导被起诉,最终同意删除了数十亿条在无痕模式下收集的用户数据,并在 Chrome 的无痕模式启动页加了更明确的说明。tips

无痕模式的正确理解是:用完即焚的临时 Cookie 空间。它解决的是"关了窗口之后不留痕迹",而不是"上网时没人知道你在干什么"。

4.9.1 "删除 Cookie"能解决什么问题

你可能遇到过这种情况:某个网站卡在一个奇怪的状态——登录一半卡死、页面显示异常、怎么刷新都不行、退出重进还是那样。

这时候"清除该网站的 Cookie"往往能解决问题。因为 Cookie 里可能存了一个损坏的 session ID 或者错误的状态标记,浏览器每次访问都带着这个坏数据,服务器就一直返回错误的结果。删掉 Cookie = 回到"从未访问过这个网站"的状态,一切重新开始。

怎么只删一个网站的 Cookie(不影响其他网站)

这比"清除所有浏览数据"精准得多——你只重置了出问题的那个网站,其他网站的登录状态不受影响。

4.9.2 Chrome "清除浏览数据"里每一项是什么

打开 Chrome 设置 → 隐私和安全 → 清除浏览数据,你会看到这些选项:

选项 是什么 删了会怎样 建议
Browsing history 你访问过的网址列表 地址栏不再自动补全这些网址 随意删,纯记录
Cookies and other site data 所有网站的 Cookie + LocalStorage 所有网站退出登录,偏好设置重置 谨慎!除非你愿意重新登录所有网站
Cached images and files 网站资源的本地缓存(图片、CSS、JS) 下次访问网站会稍慢(需要重新下载) 放心删,只影响速度不影响功能
Download history 下载记录列表(不是文件本身) 下载页面的历史清空 随意删,文件还在
Autofill form data 表单自动填充的记录(地址、姓名等) 填表时不再自动补全 看个人需求
Site settings 你对各网站的权限设置(通知、摄像头、位置等) 所有网站权限回到默认 一般不删
Hosted app data Web 应用的离线数据 离线应用数据丢失 一般不删

4.9.3 到底该删哪些

可以放心删的

因人而异的

一般不动的

4.9.4 "定期清理 Cookie"有必要吗

网上有很多文章建议"定期清理 Cookie"。这个建议的出发点是隐私——清理 Cookie 可以打断广告商的追踪链。但实际操作中:

如果你用 Chrome 且不装任何隐私扩展:定期清理 Cookie 确实能减少被追踪的程度。但代价是每次清理后所有网站都要重新登录,很烦。

如果你用 Safari / Firefox / Brave:它们已经默认阻止了第三方 Cookie(追踪用的那种),你的第一方 Cookie(登录用的)不需要清理。所以没必要定期清理。

折中方案:只清理缓存,不清理 Cookie。缓存定期清理(比如每月一次)可以释放磁盘空间、避免旧缓存导致的显示问题,同时不影响你的登录状态。

4.9.5 一个实用技巧:按时间范围清理

注意清除数据页面顶部的时间选择器(Last 15 min / Last hour / Last 24 hours / All time)。

如果你只是想清理"刚才那个出问题的网站",选"Last hour"就够了——只删最近一小时的数据,不影响之前的登录状态。"All time"是核弹级操作,除非你真的想从头开始。

不会。至少第一方 Cookie 不会——它是 Web 登录和会话管理的基础,没有替代品。

会消失的(或者说应该消失的)是第三方 Cookie。Safari 和 Firefox 已经证明了:阻止第三方 Cookie 后,网站照样正常工作,用户体验不受影响。唯一受影响的是广告追踪——而这正是应该被限制的。

但只要 Chrome 不动(占 65% 市场份额),第三方 Cookie 就不会真正消亡。这是一个商业问题,不是技术问题。

即使第三方 Cookie 被完全阻止,广告商也不会放弃追踪。他们已经在开发替代方案:

Cookie 只是追踪技术的冰山一角。阻止了 Cookie,还有指纹;阻止了指纹,还有其他方法。这是一场永无止境的猫鼠游戏。

下一章,我们就来看看比 Cookie 更隐蔽、更难防御的追踪技术:浏览器指纹。