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