本文目录导读:

我们来详细解析一下 SameSite 属性的几个经典案例,SameSite 是 HTTP 响应头 Set-Cookie 中的一个属性,用于控制 Cookie 在跨站请求(Third-party requests)中是否发送,主要用于防御 CSRF(跨站请求伪造) 攻击。
理解 SameSite 之前,必须先区分两个概念:
- 同站(Same-site): 协议(http/https)、域名(主域名+子域名)、端口号完全一致。
a.example.com和b.example.com属于同站(顶级域名.example.com相同)。 - 跨站(Cross-site): 协议、域名或端口只要有一个不同。
example.com和google.com是跨站。
三个核心值:Strict、Lax、None
SameSite 有三个可选值,我们通过三个典型案例来解释:
SameSite=Strict(严格模式)
行为: Cookie 仅在顶级导航(地址栏直接输入、点击书签) 且请求来源与目标网站完全同站时发送,任何跨站的请求(包括通过链接跳转、图片加载、表单提交)都不会携带此 Cookie。
场景: 银行的转账接口 https://bank.com/transfer
-
用户正常操作(发送 Cookie):
- 用户打开浏览器,直接在地址栏输入
bank.com并登录,浏览器设置了一个 Session ID 的 Cookie,Set-Cookie: session_id=xxx; SameSite=Strict。 - 用户在
bank.com网站上点击“转账”按钮(同站 POST 请求) → ✅ Cookie 会发送,因为发起请求的页面是bank.com本身。
- 用户打开浏览器,直接在地址栏输入
-
CSRF 攻击(不发送 Cookie):
- 黑客在另一个网站
evil.com上,放了一张图片:<img src="https://bank.com/transfer?amount=10000&to=hacker">。 - 用户访问
evil.com,浏览器加载图片,向bank.com发起跨站 GET 请求。 - ❌ Cookie 不会发送,因为请求是跨站的(
evil.com->bank.com),且 SameSite=Strict。
- 黑客在另一个网站
最安全,但用户体验差,例如用户从 google.com 点击一个广告链接跳转到 bank.com 的首页,浏览器不会发送用户的登录 Cookie,用户看到的是未登录状态,需要重新登录。
SameSite=Lax(宽松模式,Chrome 80+ 的默认值)
行为: Cookie 会在顶级导航的跨站请求中发送,但仅限于安全的方法(主要是 GET),不会在跨站的 POST 表单提交、图片/脚本加载(子资源请求)中发送。
场景: 电商网站的购物车或保持登录状态
-
用户从外部链接跳转回网站(发送 Cookie):
- 用户在
shop.com上登录,购物车信息保存在 Cookie 中(Set-Cookie: cart_id=abc; SameSite=Lax)。 - 用户收到一封促销邮件,点击链接
https://shop.com/checkout。 - 这是跨站顶级导航(邮件客户端的域名是
mail.com,但地址栏直接跳转到了shop.com)。 - ✅ Cookie 会发送,因为是 GET 方法且是顶级导航,用户直接看到了登录后的购物车内容,体验很好。
- 用户在
-
恶意的 POST 请求(不发送 Cookie):
- 黑客在
evil.com上伪装了一个按钮:<form action="https://shop.com/change_email" method="POST"><input name="email" value="hacker@evil.com"><button>领优惠券</button></form>。 - 用户点击按钮,浏览器向
shop.com发起跨站 POST 请求。 - ❌ Cookie 不会发送,因为 POST 方法不是“安全”的(会修改数据),这有效防御了这种 CSRF 攻击。
- 黑客在
安全与体验的平衡,对大多数 Web 应用(需要保持登录状态、购物车功能)Lax 是推荐的默认值。
SameSite=None(必须配合 Secure 属性)
行为: 始终发送 Cookie,无论是否是跨站请求。所有同站和跨站请求都会携带该 Cookie。
前提: 如果设置了 SameSite=None,则 Cookie 的 Secure 属性也必须设置为 true,否则浏览器会直接拒绝该 Cookie。
场景: 嵌入在第三方网站中的内容(Widget)、广告(Ad)或 CDN 资源
-
第三方分析工具:
- 你的网站
yoursite.com嵌入了 Google Analytics 的代码,GA 会请求google-analytics.com并设置一个 Cookie_ga。 Set-Cookie: _ga=GA1.2.xxx; SameSite=None; Secure- 当用户在
yoursite.com上浏览页面时,浏览器会向google-analytics.com发送跨站请求。 - ✅ Cookie 会发送,使得 GA 能够追踪用户在多个不同网站间的行为。
- 你的网站
-
支付 Iframe:
- 用户在
shop.com付款,页面内嵌了一个来自paypal.com的 iframe 用于输入信用卡信息。 - Paypal 需要设置一个 Cookie 来记住用户的支付偏好(如记住卡号)。
Set-Cookie: payment_method=visa; SameSite=None; Secure- 当 iframe 内的脚本向
paypal.com发起请求时(跨站请求,从shop.com到paypal.com)。 - ✅ Cookie 会发送,允许用户享受自动填充功能。
- 用户在
注意: 设置为 None 会暴露 Cookie 给所有第三方请求,CSRF 攻击面最大,必须依赖其他安全措施(如 CSRF Token、Referer 检查)来防御攻击。
总结表格:三种情况的跨站请求行为
| 请求类型 | 发起位置举例 | Strict | Lax | None |
|---|---|---|---|---|
| 顶级导航 GET | 用户点击 google.com 上的广告跳转到 shop.com |
❌ | ✅ | ✅ |
| 顶级导航 POST | 用户提交表格到另一个网站 (跨站) | ❌ | ❌ | ✅ |
| 子资源加载 | <img> <script> 标签请求来自 bank.com 的资源 |
❌ | ❌ | ✅ |
| AJAX / Fetch | evil.com 上的 JS 通过 fetch() 请求 api.bank.com |
❌ | ❌ | ✅ |
| Iframe 嵌入 | news.com 内嵌了 bank.com 的 iframe |
❌ | ❌ | ✅ |
重要时刻:Chrome 80 (2020 年) 的变更
- 旧版本(Chrome 80 之前): 默认行为是
SameSite=None,即跨站请求默认发送 Cookie,这使得 CSRF 攻击很容易。 - 新版本(Chrome 80+,包括 Edge、Firefox 后续跟进): 如果未设置 SameSite 属性,默认视为
SameSite=Lax。- 直接后果: 很多旧的、依赖 Cookie 与第三方网站通信的集成(如支付回调、某些 SSO 登录、WebRTC 等)在 2020 年后出现故障。
- 修复方式: 开发者需要为新接口显式设置
Set-Cookie: xxx; SameSite=None; Secure。
实际开发建议
- 你的网站只需要自己用? 设置
SameSite=Lax(或者不设置,让浏览器用默认值),这是最稳妥的。 - 你的 Cookie 是用来做 CSRF 防御的(如 CSRF Token)? 强烈建议设置
SameSite=Strict,因为 CSRF 攻击通常通过表单提交(POST)完成,严格模式刚好能阻止,但要注意,如果你有从外部页面 GET 跳转到你表单页面的需求(比如邮件链接跳转到“修改密码”页面),Strict 可能会导致 Token 丢失,此时可以考虑Lax。 - 你的服务需要被第三方网站调用? 必须设置
SameSite=None; Secure。但要注意: 这只是允许了跨站发送,你仍然需要用其他方式(如 Signature、CSRF Token、Referrer-Policy)来确保请求是来自你信任的第三方网站,而非恶意网站,你可以考虑设置更严格的Secure属性,让 Cookie 只在 HTTPS 下发送。 - API 服务(无 Cookie 场景): 如果是纯 API 使用 Bearer Token(如 JWT)在
Authorization: Bearer <token>头中传递,则完全不受 SameSite 影响,因为 SameSite 只控制Cookie头。
总结一句话:
不要随意设置 SameSite=None,除非你明确需要跨站分享 Cookie(且已做好安全评估),否则不要设置它,让浏览器使用默认的 Lax 即可。 这是防御 CSRF 最简单也最有效的一套方案。