浏览器 Web 安全基础系列
Cookie 为什么会自动携带(当前篇)
HTTP 本身不记得“上一条请求是谁发的”。用户登录成功后,服务端通常生成 Session ID,通过 Cookie 交给浏览器;浏览器之后访问匹配的地址时自动带回 Cookie,服务端才能识别用户。

一次登录发生了什么
用户提交账号密码:
POST /login
Content-Type: application/json
{"username":"alice","password":"..."}
服务端验证成功后创建 Session:
const sessionId = crypto.randomBytes(32).toString('hex');
sessions.set(sessionId, { userId: 1001 });
再通过响应头写入 Cookie:
Set-Cookie: sid=随机值; Path=/; HttpOnly; Secure; SameSite=Lax
浏览器保存后,访问同一站点时自动发送:
Cookie: sid=随机值
攻击者利用 CSRF 时,依赖的正是“浏览器自动发送”这一行为。
Cookie 中应该保存什么
常见方案是只保存随机 Session ID:
Cookie: sid=7f5a...
用户资料、权限和登录状态保存在服务端 Session 或数据库中。这样可以主动注销 Session、更新权限和踢掉设备。
也有无状态 Token 方案,但“把 JWT 放进 Cookie”并不会自动消除 CSRF。只要认证凭证由浏览器自动携带,就仍要考虑跨站请求伪造。
Cookie 的发送决策
浏览器并不是看到同一域名就发送所有 Cookie,而是依次检查名称、Domain、Path、是否过期、Secure 和 SameSite 等属性。

Domain
不设置 Domain 时通常是 Host-only Cookie,只发给设置它的主机:
Set-Cookie: sid=abc; Path=/
由 login.example.com 设置后,不会自动发送给 api.example.com。
设置:
Domain=example.com
会扩大到子域名。范围越大,受到子域名漏洞和接管问题影响的可能性也越大。
Path
Path=/admin
表示只在匹配路径的请求中发送。Path 主要用于控制发送范围,不是可靠的访问控制边界;其他路径的页面仍可能通过请求访问 /admin。
Secure
Secure
表示 Cookie 只通过 HTTPS 发送。生产登录 Cookie 应配合全站 HTTPS 使用。
HttpOnly
HttpOnly
阻止 JavaScript 通过 document.cookie 读取该 Cookie:
console.log(document.cookie); // 看不到 HttpOnly 的 sid
但浏览器发请求时仍会自动携带,所以 HttpOnly 不能防 CSRF,也不能阻止 XSS 脚本借当前登录状态调用接口。它主要降低 Session Cookie 被直接窃取的风险。
SameSite
SameSite=Lax
控制跨站请求是否携带 Cookie:
Strict:跨站请求基本不带;防护强,外部链接进入时体验可能受影响。Lax:同站请求携带,跨站顶层安全导航通常可携带,跨站表单 POST 通常不携带。None:允许跨站携带,必须同时使用Secure。
要注意 SameSite 判断的是“站”,不是“源”。localhost:3000 到 localhost:4000 虽然跨源,但仍可能同站。
推荐设置
生产环境可优先考虑:
Set-Cookie: __Host-session=随机值; Path=/; HttpOnly; Secure; SameSite=Lax
__Host- 前缀要求 Cookie 使用 Secure、Path=/ 且不能设置 Domain,有助于把 Cookie 限定在当前主机。
Express 示例:
res.cookie('__Host-session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
maxAge: 30 * 60 * 1000
});
本地纯 HTTP 实验不能完全模拟 Secure Cookie 的生产行为,可以在开发环境条件化关闭,但不要把关闭后的配置复制到线上。
Cookie 与 localStorage 的区别
localStorage 不会被浏览器自动放进 HTTP 请求,需要 JavaScript 主动读取并设置请求头;因此传统 CSRF 风险较小。但如果发生 XSS,脚本可以直接读取 localStorage 中的 Token。
Cookie 配合 HttpOnly 可以避免 JavaScript 直接读取 Session ID,但仍要使用 SameSite、CSRF Token 和 Origin 校验处理 CSRF。两种存储方式只是风险侧重点不同。
常见误区
HttpOnly 让 Cookie 不再发送
不对。它只限制 JavaScript 读取,浏览器照常发送。
SameSite=Lax 可以替代 CSRF Token
不建议。它不能覆盖同站恶意子域名、兼容性边界和业务特殊流程,应作为多层防御之一。
Cookie 设置了 Path 就等于权限隔离
不对。权限必须由服务端基于用户、角色和资源进行验证。
小结
Cookie 是浏览器保存和自动携带的一小段状态;Session 是服务端对登录状态的管理。Secure 保护传输渠道,HttpOnly 限制 JavaScript 读取,SameSite 限制跨站携带,Domain 和 Path 控制匹配范围。它们各自解决不同问题。
参考资料
Cookie 为什么会自动携带:Session、HttpOnly、Secure 与 SameSite
https://lautung.com/archives/web-security-02-cookie-login
评论