Cookie 安全标志完全指南|Secure / HttpOnly / SameSite / __Host-
Cookie 是 Web 应用程序会话管理中最常使用的机制,但如果配置不当,可能导致 会话劫持 (session hijacking)、CSRF (cross-site request forgery) 和通过 XSS 进行的令牌盗取等攻击。本文阐述了应应用于 Cookie 的四个关键标志 (Secure / HttpOnly / SameSite / __Host- 前缀) 的含义,并梳理了实现中的常见陷阱。
Set-Cookie 头结构
当服务器在浏览器中设置 Cookie 时,它在 HTTP 响应中返回如下的标头。
Set-Cookie: session_id=abc123; Path=/; Domain=example.com; Expires=Wed, 22 Apr 2026 10:00:00 GMT; Secure; HttpOnly; SameSite=Lax
有多个用分号分隔的属性,大致可分为以下两种。
- 作用域属性:Path / Domain / Expires / Max-Age — 决定 Cookie 何时何地发送
- 安全属性:Secure / HttpOnly / SameSite — 限制传输/访问
Secure — 仅通过 HTTPS 发送
具有 Secure 属性的 Cookie 仅在 HTTPS 连接时 由浏览器发送到服务器。如果没有它,当受害者通过 http:// 访问网站时,Cookie 以明文形式传输,会话 ID 可能会通过中间人 (Man-in-the-Middle) 攻击被窃取。
金科玉律:必须附加到身份验证 cookie。在本地开发中,localhost 即使没有 HTTPS 也会发送 Secure cookie,但只要假设生产环境使用 HTTPS,就不会有问题。
HttpOnly — 无法从 JavaScript 访问
添加 HttpOnly 标志可防止通过 document.cookie 读取。这可以防止 XSS 攻击注入的 JavaScript 窃取 Cookie。
由于 XSS 仍然是可能的漏洞,请将 HttpOnly 标志视为会话 Cookie 的必须项。如果您的 JavaScript 代码需要读取 Cookie 值(例如 CSRF 令牌),标准做法是创建单独的只读 Cookie 或通过 <meta> 标签 传递值。
SameSite — 跨站请求中的传输控制
SameSite 属性是 CSRF 防护的核心。值有以下三种:
| 值 | 行为 | CSRF 防护 |
|---|---|---|
Strict | 根本不向跨站请求发送(即使来自外部链接) | 最强大 |
Lax (默认) | 仅在顶级 GET 导航中发送(链接点击 OK,POST 表单 NG) | 强 |
None | 随所有跨站请求发送(需要Secure) | 无 |
2020年以后的现代浏览器将未指定的SameSite视为Lax,因此即使不显式指定也能获得最低限度的CSRF保护。但为了明确意图,最好显式设置。
当在 SSO 集成或 iframe 嵌入中使用 SameSite=None 时,必须同时添加 Secure—这是现代浏览器的要求。没有 Secure 的 SameSite=None 的 Cookie 会被浏览器拒绝。
__Host- / __Secure- 前缀
当 Cookie 名称以 __Host- 开头时,浏览器会强制执行以下三个条件。
Secure标志是必需的- 不应该添加
Domain属性(即仅限发送请求的准确主机) Path=/是必需的
这些提供强有力的保证:「不能从其他子域名被覆盖」「不能通过Host头欺骗来设置Cookie」。对于会话Cookie,添加像__Host-session这样的前缀最为稳健。
另一个 __Secure- 前缀仅强制必需的Secure标志 (没有Domain / Path限制)。
4096字节限制
根据 RFC 6265,Cookie 的值建议为 总共 4096 字节。如果将大的 JSON 或数组放入 Cookie 中并超过此限制,浏览器可能会悄悄截断它们。最佳做法是在服务器端会话中存储大数据,只在 Cookie 中放入会话 ID。
实现示例:身份验证会话 Cookie
正确配置的身份验证 Cookie 如下所示:
Set-Cookie: __Host-session=eyJ0eXAi...; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=Lax
__Host-: 防止子域名污染和主机欺骗Path=/: 在整个网站上可访问Max-Age=3600: 1 小时后过期Secure: 仅通过 HTTPS 发送HttpOnly: 无法从 JavaScript 访问SameSite=Lax: 不在跨站点 POST 请求中发送 (CSRF 保护)
PHP (Laravel) 示例
// config/session.php
return [
'secure' => true, // Secure フラグ
'http_only' => true, // HttpOnly フラグ
'same_site' => 'lax', // SameSite=Lax
'path' => '/',
'cookie' => '__Host-session',
];
Node.js (Express) 示例
const session = require('express-session');
app.use(session({
name: '__Host-session',
secret: process.env.SESSION_SECRET,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'lax',
path: '/',
maxAge: 3600 * 1000,
},
}));
检查现有网站 Cookie 设置的方法
使用 DevLab 的 Cookie 检查工具,您可以立即验证您的网站或第三方网站上的 Cookie 是否设置正确。只需输入 URL,该工具就会分析所有返回的 Set-Cookie 标头,并显示如下诊断。
- 每个 Cookie 的 Secure / HttpOnly / SameSite 有无
- 像 SameSite=None 但没有 Secure 这样的违规
- __Host- 前缀的一致性
- 4096字节超出警告
- 总体摘要(Secure比率 / HttpOnly比率 / SameSite分布)
总结
Cookie 安全标志不应该随意设置,而应该基于理解攻撃场景和相应的防御措施来配置。至少,生产环境中的身份验证会话 Cookie 应该包含 Secure + HttpOnly + SameSite + __Host- 前缀 + 短 Max-Age。对于现有网站的设置审查,我们推荐使用 Cookie 检查工具。