Cookie 仍然是网络上最常配置错误的安全控制之一。单个缺失的属性可能会使您的应用程序遭受会话劫持、CSRF 或跨站点信息泄漏。现代浏览器已经推出了更严格的默认值,但了解每个属性并正确组合它们对于纵深防御至关重要。
核心安全属性是 Secure、HttpOnly、SameSite 和 __Host- / __Secure- 前缀。每一个都有不同的目的,当它们结合起来时效果最好。
同一站点属性
SameSite 控制何时在跨站点请求中发送 cookie。它是针对 CSRF 攻击的主要防御措施。
Set-Cookie: session=abc123; SameSite=Lax
| 价值 | 行为 | 使用案例 |
|---|---|---|
| 占位符_0 | 仅针对同一站点请求发送(顶级导航和子资源) | CSRF 代币、敏感账户操作 |
Lax(默认) | 发送用于顶级 GET 导航,而不是跨站点 POST、图像、脚本或 iframe | 常规会话 cookie |
| 占位符_0 | 发送所有跨站点请求;需要 Secure 标志 | 第三方小部件、嵌入式内容、API 集成 |
SameSite=Lax 是现代浏览器(Chrome、Edge、Firefox)中的默认值,适用于大多数会话 cookie。将 Strict 用于 CSRF 令牌和关键操作。仅当需要第三方嵌入时才使用 None — 并且始终将其与 Secure 配对。
安全标志
Secure 属性确保 cookie 仅通过 HTTPS 传输。如果没有它,cookie 可能会通过未加密的连接被拦截——在公共 Wi-Fi 上尤其危险。
Set-Cookie: session=abc123; Secure
无法从 http:// 源设置此标志。它必须从 HTTPS 页面上下文设置。一个常见的错误是在开发期间在 localhost 上设置 Secure (有效),但使用混合内容进行部署会导致 cookie 在生产中通过 HTTP 提供服务。
使用 SameSite=None 时,Secure 标志是必需的。浏览器拒绝没有 Secure 的 SameSite=None cookie。
仅 Http 属性
HttpOnly 阻止 JavaScript 通过 document.cookie 进行访问。这是针对基于 XSS 的会话盗窃的主要防御措施。 XSS漏洞仍然可以执行任意JavaScript,但攻击者无法直接读取会话cookie。
Set-Cookie: session=abc123; HttpOnly
代价是客户端 JavaScript 无法读取或写入 HttpOnly cookie。对于检查 cookie 的 SPA 身份验证流程,解决方法是使用检查身份验证状态的专用 API 端点,或使用存储在内存中的基于令牌的身份验证。如果可以避免的话,切勿将会话令牌存储在 XSS 可以访问的地方。
路径和域范围
Path 属性将 cookie 限制为特定的 URL 路径。 Domain 属性控制哪些子域接收 cookie。
Set-Cookie: app_session=xyz; Path=/app; Domain=.example.com
对站点范围的 cookie 使用 Path=/ 或限制到特定路径,例如 /admin。如果设置得太宽泛,Domain 属性会很危险。 Domain=.example.com 使所有子域都可以访问 cookie,包括 staging.example.com 或 dev.example.com — 这些子域通常不太安全。仅当明确需要子域共享时才设置广泛的 Domain 。
Cookie 前缀
Cookie 前缀提供客户端代码无法绕过的协议级保证。
Set-Cookie: __Host-session=abc123; Secure; Path=/
Set-Cookie: __Secure-csrf=xyz; Secure
| 前缀 | 要求 |
|---|---|
| 占位符_0 | 必须是安全的,Path=/,无域属性 — 范围仅限于源 |
| 占位符_0 | 必须是安全的 — 范围仅限于具有安全性的域 |
使用 __Host-session 作为会话令牌。该前缀确保 cookie 的范围仅限于单一来源,从而防止子域攻击。浏览器在协议级别强制执行这些要求——没有 JavaScript 可以去除前缀。
大小限制和 CHIPS(分区 Cookie)
浏览器强制执行限制:每个 cookie 大约 4KB,每个域 50-150 个 cookie,每个源 10-50 个 cookie。通过仅存储引用(会话 ID、资源标识符)而不是将数据直接嵌入 cookie 值来保持在这些限制之内。
CHIPS(具有独立分区状态的 Cookie)引入了 Partitioned 属性。这会为每个顶级站点创建一个单独的 cookie jar,防止跨站点跟踪,同时允许嵌入式第三方服务维护状态。
Set-Cookie: widget_pref=dark; Secure; SameSite=None; Partitioned; Path=/
浏览器支持包括 Chrome 114+、Edge 114+ 和 Opera。 CHIPS 非常适合需要状态但不启用跨站点跟踪的支付 iframe、嵌入式地图和第三方聊天小部件。
跨站点和跨源行为
同站点和同源是影响cookie发送的不同概念。 https://app.example.com 和 https://api.example.com 是同一站点(相同的可注册域)但跨源(不同的主机名)。 SameSite 规则在站点上进行评估,而不是在原点进行评估。
对于包含 cookie 的跨源获取请求:
fetch("https://api.example.com/data", {
credentials: "include",
});
这要求服务器以 Access-Control-Allow-Credentials: true 进行响应。 Safari 的智能跟踪预防 (ITP) 和 Firefox 的增强跟踪保护 (ETP) 对 cookie 生命周期和跨站点访问施加了额外的限制,特别是对于无需用户交互的 cookie。
实用配置菜谱
// Express.js
app.use(session({
name: "__Host-session",
secret: process.env.SESSION_SECRET,
cookie: {
secure: true,
httpOnly: true,
sameSite: "lax",
path: "/",
},
}));
// Next.js API route
export async function GET(request) {
return new Response(JSON.stringify({ ok: true }), {
headers: {
"Set-Cookie":
"session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/",
},
});
}
| Cookie 类型 | 配置 |
|---|---|
| 认证 | 占位符_0 |
| CSRF 代币 | 占位符_0 |
| 第三方小部件 | 占位符_0 |
测试与调试
浏览器开发工具(“应用程序”选项卡)显示所有 cookie、它们的属性以及它们是否标记为安全或 httpOnly。对于命令行测试:
# Check cookie behavior
curl -v -c cookies.txt -b cookies.txt https://example.com/login
网络选项卡的响应标头显示 Set-Cookie 标头。检查所有预期的属性是否都存在。使用 OWASP ZAP 或类似工具进行自动 cookie 安全扫描,作为 CI 管道的一部分。
概括
深度防御 cookie 策略结合了所有可用属性。大多数会话 cookie 的默认建议是 HttpOnly + Secure + SameSite=Lax。对于 CSRF 令牌,请添加 __Host- 前缀和 SameSite=Strict。为不可避免的第三方上下文保留 SameSite=None 。使用浏览器开发工具和自动扫描仪进行定期审核可确保您的 cookie 配置在浏览器不断发展其隐私和安全默认设置时保持安全。

