侧边栏壁纸
博主头像
一笑痕

人生若只如初见,
是可喜亦或者是可悲?

  • 累计撰写 81 篇文章
  • 累计收到 7 条评论

跨站能带上的只有 None 加 Secure 这一种

2026-9-21 / 0 评论 / 12 阅读

跨站能带上的只有 None 加 Secure 这一种

接口在 http://127.0.0.1:8812 下发 Cookie,页面从 http://localhost:8811 跨站发请求,两个端口都是本机真实服务,请求由本机 Chrome 发出,服务端把每条到达请求的方法与路径记下来,加上来源页和 Cookie 名字,Cookie 只记名字不记值。整套跑法在 tools/verify-cookie-scope.mjs,制表脚本 tools/verify-cookie-scope-table.py

六种属性里,只有 None 加 Secure 落了盘

下发的属性 跨站 fetch(credentials: include)
不写 SameSite(默认 Lax) 没带
SameSite=Lax 没带
SameSite=Strict 没带
SameSite=None; Secure 带上
SameSite=None 没加 Secure 没带
HttpOnly; SameSite=None; Secure 带上

前两行与第三行的区别在浏览器行为上不明显,在服务端记录上却能分清:不写 SameSite 的那条 Cookie 从来没有出现在任何后续请求里,说明它在跨站响应里就被丢掉了,与显式写 Lax 一样被拒收。SameSite=None 却没加 Secure 的那条也是同样的下场,名字一次都没出现过。整张表里只有带 None 与 Secure 的两条真正落盘并随请求回来了。

路径前缀、credentials 与删除时机

场景 结果
Path=/a 的 Cookie,请求 /a/echo 带上
Path=/a 的 Cookie,请求 /echo 没带
SameSite=None 的 Cookie,fetch 没写 credentials 没带
Max-Age=0 之前 带上
Max-Age=0 之后 没带

Path 那一行与第三行说明两件事:Cookie 的可见范围按路径前缀判,请求路径不在前缀里就完全看不到;跨站请求即使 Cookie 本身合法,少了 credentials: include 也不会带上,这一条经常被当成 CORS 头没配对,其实开关在发请求那一侧。Max-Age=0 的删除立即生效,删除后的请求里名字就不见了。

document.cookie 里为什么少一个 f_httponly

同一批 Cookie 在顶层导航里表现完全不同。页面自己跳转(同站)时,服务端收到的名字是 sid, c_none_secure, c_httponly, f_default, f_lax, f_strict, f_none, f_httponly,八条全到。从 localhost 那个页面发起的跨站跳转,服务端收到的是 sid, c_none_secure, c_httponly, f_default, f_lax, f_none, f_httponly,少了 f_strict,这正是 Lax 与 Strict 的分界:Lax 允许顶层导航携带,Strict 不允许。

document.cookie 那一侧是另一套限制。第一方页面里读出来的字符串是 sid=abc123; c_none_secure=1; f_default=1; f_lax=1; f_strict=1; f_none=1,五个 f_ 名字里唯独少了 f_httponly,而服务端在同一个页面的后续请求里收到了它。HttpOnly 的含义就在这里:脚本读不到,请求照样带。另外页面跑在 localhost、Cookie 属于 127.0.0.1,所以 document.cookie 里也读不到 c_ 开头的那些,前半段测出来的「浏览器可见:否」就是这个原因,与 HttpOnly 无关,别把两件事混在一起看。

本机 Chrome 153 上的三条边界

要给跨站请求下发 Cookie,属性必须写全 SameSite=None; Secure,其余组合在本次实测里都被丢弃。要读 document.cookie 又不想被脚本拿走的值,加 HttpOnly。跨站 fetch 想带上 Cookie,credentials: include 不能漏,这比调 CORS 响应头更常见。

这几组数字全部来自本机 Chrome 153 的默认配置,第三方 Cookie 策略近两年改动频繁,换版本或换 Safari、Firefox 结果可能不同,这一部分我没有跨浏览器验证。日志里那条 sid=abc123 是早前测试留在浏览器 profile 里的 Cookie,正好顺带说明同一 profile 的历史 Cookie 会一起带上,做这类实验时最好用干净 profile。Secure 属性在 http://127.0.0.1 上能被正常接收并回传,因为本机地址被浏览器当成可信来源,换成一个真实域名走 http,这一条就没法照搬。

来源:tools/verify-cookie-scope.mjs 的服务端日志(页面跑在 http://localhost:8811,接口在 http://127.0.0.1:8812,跨站)

=== 一、跨站 fetch(页面 localhost → 接口 127.0.0.1,credentials: include)===
场景                                这一条 Cookie 带上了吗
不写 SameSite(默认 Lax)             没带
SameSite=Lax                    没带
SameSite=Strict                 没带
SameSite=None; Secure           带上
SameSite=None 没加 Secure         没带
HttpOnly + None + Secure        带上

=== 二、Path 作用域与删除 ===
Path=/a 的 Cookie,请求 /a/echo       带上(服务端看到:c_path,c_none_secure,c_httponly)
Path=/a 的 Cookie,请求 /echo         没带(服务端看到:c_none_secure,c_httponly)
SameSite=None 的 Cookie,但 fetch 没写 credentials没带(服务端看到:(无))
Max-Age=0 之前                      带上(服务端看到:c_none_secure,c_httponly,c_del)
Max-Age=0 之后                      没带(服务端看到:c_none_secure,c_httponly)

=== 三、顶层导航(同一个浏览器,两种发起方)===
发起页面 http://127.0.0.1:8812/page  请求 /echo?case=nav_same_site
    服务端收到 Cookie: ['sid', 'c_none_secure', 'c_httponly', 'f_default', 'f_lax', 'f_strict', 'f_none', 'f_httponly']
发起页面 http://localhost:8811/  请求 /echo?case=nav_from_localhost
    服务端收到 Cookie: ['sid', 'c_none_secure', 'c_httponly', 'f_default', 'f_lax', 'f_none', 'f_httponly']

=== 四、第一方页面(http://127.0.0.1:8812/page)里 document.cookie ===
响应头种下: f_default=1; Path=/ | f_lax=1; Path=/; SameSite=Lax | f_strict=1; Path=/; SameSite=Strict | f_none=1; Path=/; SameSite=None; Secure | f_httponly=1; Path=/; HttpOnly
同站导航时服务端收到: sid, c_none_secure, c_httponly, f_default, f_lax, f_strict, f_none, f_httponly

浏览器侧取回的原始结果(tools/cdp-run.mjs 读 window.__results):
{"documentCookie":"sid=abc123; c_none_secure=1; f_default=1; f_lax=1; f_strict=1; f_none=1","visible":["sid","c_none_secure","f_default","f_lax","f_strict","f_none"]}
    🤞 分享