限制浏览器跨站携带 cookie,以削减暴露面。

cookie 的 Secure 与 SameSite

Secure 与 SameSite 都不是服务端执行的检查。它们是用户代理在决定「要不要把这枚 Cookie 附到这条出站请求上」时遵循的指令,而服务端只能看到结果:要么有一个 Cookie 头,要么什么都没有。这种不对称正是它们存在的理由,也正是它们的陷阱。 两个标志位都很便宜,也都坏得很安静:缺了 Secure,一条明文请求路上的任何人都能拿走会话;SameSite 缺失或太松,状态变更请求就仍然能被另一个源触达;SameSite 太严,又会让单点登录赖以工作的跳转链路断掉。要选的,是你更愿意去排查哪一种。 Secure 挡住明文那一份 Secure 要求用户代理只把这枚 Cookie 附到 https 协议的请求上,于是一条明文请求——用户点开的 http:// 链接、HSTS 生效之前下发的跳转、混用的内容子资源——就不会带上会话令牌,路径上的旁观者无从读取。MDN 记下了那个例外:localhost 被视为可信,所以开发期 Secure Cookie 照样会走 http://localhost。实验从客户端这一侧把规则演示出来:一个存了五枚 Cookie 的 jar 在明文 http 上只发出三枚,把带 Secure 的两枚扣住;而协议一旦换成 https,五枚全部附上。 Secure 不做什么,同样值得说清。它不是存储规则——浏览器照样存下这枚 Cookie,稍后在 HTTPS 上发送。它不是完整性规则,也不能代替 HttpOnly,后者才是让 document.cookie 与 XSS 载荷读不到那个值的东西。它也救不了一条已经在明文上发出、Set-Cookie 头在途中被改写的响应;这正是为什么 Secure 应当与 HSTS、与整站跳转 HTTPS 一起上,而不是拿它顶替。 ...

六月 17, 2027 · 2 分钟 · XB Field Notes
一枚受 path、domain 与标志位约束、只传给该去之处的 Cookie。

Cookie 作用域让会话留在该待的地方

一枚 Cookie 的作用域,就是「哪些请求会带上它」这件事的集合。Domain、Path、Secure、SameSite 每一个属性都在从这个集合里划掉请求,浏览器会把这四条规则全部过完,才决定写不写 Cookie 头。作用域因此是 Web 栈里最便宜的一道控制:运行时零成本,却直接减少了会话令牌穿越你不拥有的网络的次数。 便利总是往反方向拉。www、api、shop 要共用登录态,于是有人写下 Domain=example.com;单页应用挂在 /app 下,于是有人写下 Path=/;某个页面为了一条横幅要用会话,于是有人写下 SameSite=None。每一次放宽单独看都说得通,而每一次都新增了一批能读到、重放或覆写这枚令牌的主机与路径。 域名是后缀匹配,不是通配符 RFC 6265 讲得很直白:Domain=example.com 会让用户代理把这枚 Cookie 发给 example.com、www.example.com 和 www.corp.example.com。前导的点会被忽略——原文是「即使那个字符并不被允许」——所以带点与不带点两种写法是同一枚 Cookie。那个点从来就不是通配符。实验直接把这条裂缝摆了出来:Python 的 http.cookies 会原样保留 .example.com,而 RFC 的 domain-match 算法会先把它剥掉;于是把作用域逻辑建立在原始头部字符串上的服务端,会和浏览器对同一枚 Cookie 得出不同结论。 不写 Domain,得到的是 host-only Cookie,RFC 说它「只回给源服务器」——这才是窄的默认值,也正是你想要的。宽的那一版会把会话交给每一个同级子域,包括没人当成应用一部分的那些:状态页主机、文档站主机、市场部自己维护的 CMS。实验表格里,Domain=example.com 会挂到 evil.example.com 上,而从 www.example.com 设下的 host-only Cookie 根本到不了 shop.example.com。另外,Domain 属性必须与设置它的主机 domain-match,所以放宽只能朝父域走、不能横向走:从 www.example.com 发出 Domain=shop.example.com 会被直接拒绝。 ...

十月 25, 2026 · 1 分钟 · XB Field Notes