目标
SameSite 各模式在不同请求形态下的表现差异,注定它是一场可以亲手做的黑箱实验:种下三种 Cookie、从第二个源发起探测、读取服务端实际收到了哪几个。实验结果能让加固方案建立在证据而非道听途说之上,也能向团队解释为什么 Lax 是默认、Strict 会把邮件链接点进来的用户登出。
步骤要点
- 在站点 A 的 /set 接口用 res.cookie 分别种下 strict、lax、none 三种 SameSite 的 Cookie,先在同源 /echo 请求确认三个都能收到。
- 在站点 B 的页面里用 img、iframe、带 credentials 的 fetch 三种跨站子资源请求探测 A,服务端日志应只有 none 到达。
- 测顶层导航:从 B 链接到 A 的 GET 请求里 lax 会携带而 strict 不会,这正是 Lax 作为安全默认值的理由。
- 把真实会话 Cookie 显式加固为 lax(httpOnly、secure 全开),重跑跨站探测确认会话 Cookie 不再随子资源外泄。
- 用自动提交的跨站表单 POST 复现 CSRF 场景,加固后该请求不带会话 Cookie,服务端以未认证拒绝,此类 CSRF 向量关闭。
排错提示
SameSite=None 的 Set-Cookie 被浏览器丢弃是因为 None 必须配 Secure 与 HTTPS,先给探测页配本地证书;各浏览器行为不一致本身就是实验结论,在支持的浏览器矩阵上跑一遍并记录结果,默认选全引擎都尊重的 Lax;Strict 弄坏邮件链接回流的用户体验时,会话 Cookie 保持 Lax,Strict 只留给敏感页面的短时反 CSRF 令牌。
适用边界
SameSite 属于 CSRF 缓解而非认证本身,状态变更的 POST 端点仍需配合 CSRF 令牌;老旧内嵌浏览器完全忽略 SameSite,这类客户端重要的场景要做能力检测或改用令牌 API。
代码示例
Request shape | strict | lax | none
------------------------------|--------|-----|-----
same-site fetch | Y | Y | Y
cross-site <img> subresource | - | - | Y
cross-site iframe | - | - | Y
cross-site fetch +credentials | - | - | Y
top-level GET navigation | - | Y | Y
cross-site form POST | - | - | Y