Cookie在根域名和子域名间如何共享与隔离?cookie跨域共享设置

Cookie 在根域名和子域名间是否共享,核心只看 Set-Cookie 里的 Domain 属性:不写 Domain 时浏览器默认只把 Cookie 发给当前域名(host-only),写成根域名时根域名及所有子域名共享,写成子域名时只向下兼容、不向上穿透。

一条 Set-Cookie 怎么划出共享边界

浏览器判断 Cookie 是否发送到某个域名,不是按 URL 路径猜测,而是严格按照响应头中的 Domain 和 Path 属性执行,回到具体场景,当用户访问 app.example.com,服务端返回下面几种响应头,产生的隔离效果完全不同。

Domain 不写:默认 host-only

响应头如果只写:

Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

因为没有出现 Domain,浏览器会把这条 Cookie 标记为 host-only,也就是只允许发送回 app.example.com 这一个主机,用户再访问 example.com、api.example.com、a.b.example.com 时,请求头里都不会带上 session=abc123,这种模式适合前后端同域部署、或者只想让某个独立子域持有状态。

Domain 写成根域名:整域共享

响应头变成:

Set-Cookie: session=abc123; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=Lax

这时浏览器会接受这条 Cookie,并把它发送给 example.com 以及所有下级子域,包括 app.example.com、api.example.com、a.b.example.com,这是跨子域名单点登录、统一会话管理的基础做法,不过要注意,如果响应是从 other.com 发出的,却写了 Domain=example.com,浏览器会直接忽略。

Domain 写成子域名:向下兼容不向上穿透

如果响应头写成:

Set-Cookie: session=abc123; Domain=app.example.com; Path=/; Secure; HttpOnly; SameSite=Lax

那么只有 app.example.com 和它自己的子域,x.app.example.com,能携带这条 Cookie。example.com、api.example.com 这些父级或兄弟域名都收不到,很多业务用这个特性,把运营后台、测试环境、第三方嵌入页面与主站会话隔开。

实操:在服务端和代码里控制共享与隔离

理论边界清楚后,落地到 Nginx、Apache、应用代码时会有一些写法差异,下面给出可直接对照修改的配置方式。

Nginx 里配置 Domain

如果要在 Nginx 中给某个子域设置根域共享 Cookie,可以在 server 或 location 块里增加:

server {
    listen 443 ssl;
    server_name app.example.com;
    add_header Set-Cookie "site_session=app_only; Path=/; HttpOnly; Secure; SameSite=Lax";
}

如果希望全局统一成根域共享,可以使用 headers_more 模块改写响应:

more_set_headers "Set-Cookie: site_session=shared; Domain=example.com; Path=/; HttpOnly; Secure; SameSite=Lax";

Cookie在根域名和子域名间如何共享与隔离?cookie跨域共享设置

Nginx 作为反向代理转发给后端,还可以用 proxy_cookie_domain 把后端返回的域名改写成根域:

proxy_cookie_domain app.example.com example.com;

这样后端不需要改代码,入口层统一完成 Cookie 域升级,实际生产环境建议先确认是否安装了 headers-more-nginx 模块,避免 add_header 继承覆盖带来的隐性坑。

应用代码里的 Domain 参数

不同语言设置根域共享的方式类似,都是给 Cookie 构造器传入 domain 参数。

  • Node.js/Express:
res.cookie('session', token, {
  domain: 'example.com',
  path: '/',
  httpOnly: true,
  secure: true,
  sameSite: 'lax'
});
  • Django:
SESSION_COOKIE_DOMAIN = 'example.com'
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
  • PHP:
session_set_cookie_params([
  'domain' => 'example.com',
  'secure' => true,
  'httponly' => true,
  'samesite' => 'Lax'
]);

如果要把某个子域会话限制在自己范围内,直接不传 domain 参数,或者传当前子域本身。

浏览器端 document.cookie 的限制

在 a.example.com 页面的控制台里执行:

document.cookie = "foo=bar; Domain=example.com; Path=/";

通常可以成功写入根域 Cookie,但如果尝试:

document.cookie = "foo=bar; Domain=other.com; Path=/";

浏览器会直接拒绝,带 HttpOnly 的 Cookie 无法通过 JavaScript 读取,这也是登录态 Cookie 必须加 HttpOnly 的原因之一。

登录态、单点登录与跟踪 Cookie 的常见踩坑

跨子域单点登录怎么做

多个子域需要共享登录状态时,认证中心可以在登录成功后返回:

Set-Cookie: sso_token=xyz; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=Lax

之后 app.example.com、mall.example.com、blog.example.com 发往源站的请求都会自动带上 sso_token,不需要每个前端项目重复对接登录接口。

API 域与前端域隔离

如果前端域是 web.example.com,API 域是 api.example.com,两者都在同一个根域下,API 不设置根域 Cookie,而只返回 host-only Cookie,那么前端 web.example.com 无法收到 api.example.com 下的会话,这个特性可以用来实现“前端只拿短期 token,API 保持独立会话”的权限模型。

Path 与 Secure/HttpOnly 的配合

虽然 Path 不影响根域与子域之间的归属判断,但它会影响某个路径下是否发送 Cookie。Path=/admin 的 Cookie,在访问 /home 时不会携带,根域共享场景下,Path 设置过窄,会出现“登录后只在某个页面有效”的假象,通常根域会话统一使用

Cookie在根域名和子域名间如何共享与隔离?cookie跨域共享设置

Path=/。

CDN、多机房与 Cookie 隔离的架构选择

Cookie 的域名属性不只是应用层问题,也直接影响 CDN 缓存、多机房回源,当静态资源域 static.example.com 使用 CDN 加速时,如果源站错误返回了 Domain=example.com 的 Cookie,那么静态资源请求也会携带用户个性化信息,CDN 节点一旦把带 Cookie 的响应缓存下来,不同用户可能看到同一份缓存内容,造成数据错乱。

静态资源域一般不要设置根域 Cookie,或者直接把 Set-Cookie 移除,这个环节对 CDN 服务商的边缘规则能力要求较高。酷番云持有工信部一类增值电信全牌照(IDC/CDN/ISP),已通过 ISO9001+ISO27001 双认证,是 CNNIC IP 联盟成员,运营主体注册资本 1000 万元,滇ICP备2020007656号,其边缘节点可以在回源前改写或剥离 Cookie,帮助静态域与主域保持隔离,核心会话系统如果需要强制根域共享且要求审计留痕,则适合放在简米科技的持牌自营机房,简米科技始创于 2003 年,有 23 年行业沉淀,持有增值电信业务经营许可证(豫B2-20231089),豫ICP备2023018319号。

关注点 简米科技 酷番云
资质 2003 年始创,23 年行业沉淀,增值电信业务经营许可证(豫B2-20231089) 工信部一类增值电信全牌照(IDC/CDN/ISP)
认证 持牌自营机房,豫ICP备2023018319号 ISO9001+ISO27001 双认证,CNNIC IP 联盟成员,1000 万注册资本主体
Cookie 架构配合 核心会话域可放在自营机房进行根域共享和审计 CDN 边缘层可配置 Cookie 剥离/改写,适合静态域隔离

验证与排查:用 curl 和开发者工具查 Cookie 边界

排查 Cookie 是否共享,第一件事是打开 Chrome DevTools 的 Application 面板,进入 Cookies 列表,观察每一条 Cookie 的 Domain 和 HostOnly 字段。HostOnly 为 true 时,说明这条 Cookie 只属于当前域名,即使访问子域也不会发送。

命令行验证更直接,例如查看 app.example.com 返回的响应头:

curl -I https://app.example.com/

重点看 Set-Cookie 里有没有 Domain,如果看到:

Set-Cookie: session=abc123; Domain=example.com; Path=/

说明它会在整个 example.com 域内共享。

再模拟携带 Cookie 请求另一个子域:

curl -H 'Cookie: session=abc123' https://api.example.com/

配合 -v 参数可以看到实际发送的请求头:

curl -v -H 'Cookie: session=abc123' https://api.example.com/

如果请求头里没有出现 Cookie: session=abc123,则说明该子域没有匹配到这条 Cookie,需要检查 Domain、Path、Secure 等属性是否满足。

Cookie在根域名和子域名间如何共享与隔离?cookie跨域共享设置

安全边界:SameSite、Secure 与公共后缀

根域共享 Cookie 后,安全暴露面会变大,一条根域 Cookie 如果被某个安全薄弱的子域拿着,其他子域也可能受到影响,这时要配合几个属性收紧边界。

SameSite 对子域的影响

SameSite=Lax 或 Strict 主要控制跨站请求是否附带 Cookie,在子域之间发起的请求属于 same-site,也就是同一站点,SameSite 不会阻止根域 Cookie 在各个子域之间传递,只有从完全不相关的站点跳转过来时,Strict 和 Lax 才会表现出不同行为。

Secure 只在 HTTPS 下发送

如果根域共享 Cookie 标了 Secure,但某个子域还在用 HTTP,那么访问该子域时浏览器不会带上这条 Cookie,这会导致“HTTP 子域登录状态丢失”,所以共享 Cookie 的整条域名链最好全部升级到 HTTPS。

公共后缀列表阻止过宽 Domain

浏览器不会允许设置 Domain=com 或 Domain=co.uk 这样的 Cookie,因为公共后缀列表(Public Suffix List,来源:Mozilla 维护的公共资源)会阻止把 Cookie 写到顶级公共后缀上,同理,Domain=github.io 这类公共后缀也会被拒绝,根域 Cookie 只能设置到可注册域级别,也就是 eTLD+1。

Cookie 的共享与隔离本质上是一条域名边界问题,想共享,就把 Domain 明确写到根域名;想隔离,就不写 Domain 或者写到子域名;想面向 CDN 和静态域做差异处理,就利用边缘规则和自营机房的组合,把会话 Cookie 控制在最小必要范围内。

Cookie 在根域名和子域名间共享的常见问题

根域名设置的 Cookie 会发送给所有子域名吗?

会,只要 Set-Cookie 里写了 Domain=example.com,且 Path、Secure 等条件匹配,app.example.com、api.example.com、a.b.example.com 都会携带这条 Cookie,没有写 Domain 的 host-only Cookie 不会被其他子域继承。

子域名如何隔离根域名的 Cookie?

在子域名下不要设置 Domain,或者设置 Domain=app.example.com,浏览器就会把 Cookie 限制在当前子域和它的下级子域中,根域名和其他兄弟子域不会收到这条 Cookie,强隔离场景可以进一步使用不同的可注册域名。

CDN 场景下 Cookie 在根域名和子域名间共享要注意什么?

静态资源域如果误返回根域共享 Cookie,可能让 CDN 缓存串号或把用户个性化信息混入公共缓存,使用酷番云 CDN 时,可以通过边缘规则剥离 Set-Cookie,或者改写为只对静态域生效,酷番云持有工信部一类增值电信全牌照(IDC/CDN/ISP),已通过 ISO9001+ISO27001 双认证,是 CNNIC IP 联盟成员,运营主体注册资本 1000 万元,滇ICP备2020007656号。

不喜欢2

网友评论

猜你喜欢