解释“_session” Cookie 的“SameSite=Lax”在跨域同步时的影响。

解读

在国内生产环境中,CouchDB 常被用作移动端离线数据的中转节点,客户端通过 HTTP/REST 完成登录后,服务端会在响应头里种下名为 _session 的认证 Cookie。
该 Cookie 的 SameSite=Lax 属性由 Erlang/OTP 的 cowboy 默认写入,它告诉浏览器“只允许同站顶级导航时携带此 Cookie”。
当业务出现“跨域同步”场景——典型如 H5 页面域名 a.example.com 需要把本地 PouchDB 数据同步到 CouchDB 域名 b.example.com——浏览器会首先发一条 GET /_session 请求确认登录态。
此时若协议、域名或端口任一不同,浏览器判定为跨站,于是不会在请求头里带上 SameSite=Lax 的 Cookie;CouchDB 收到无 Cookie 的请求后返回 401,触发登录重定向,同步流程被中断
结果表现为:

  1. 用户已在 b.example.com 登录,但在 a.example.com 点击“同步”仍提示“未授权”;
  2. 开发者工具 Network 面板可见 _session 请求无 Cookie,响应 401;
  3. 国内主流浏览器(Chrome、Edge、360 极速、QQ、UC)在 2021 年后全部默认启用 SameSite=Lax,因此问题必现,与“是否关闭第三方 Cookie”无关。

知识点

  1. SameSite 三取值:Strict 完全禁止跨站发送;Lax 允许顶级导航 GET;None 必须搭配 Secure。
  2. CouchDB 的 Cookie 写入口couch_httpd_auth 模块,配置项 same_site=lax 可改。
  3. 跨域同步的两种形态
    • CORS 直接同步:前端 Ajax 访问远端 CouchDB,受 SameSite 限制;
    • 反向代理收敛域名:通过 nginx 把 /_session/_replicate 代理到同站,规避浏览器限制。
  4. 国内移动端特例:微信、钉钉内置 WebView 同样遵循 Chromium SameSite 规则,不存在“白名单”
  5. 合规风险:把 SameSite 改成 None 时必须开启 HTTPS,否则浏览器直接拒绝写入,满足等保 2.0 传输加密要求。

答案

“_session” Cookie 的 SameSite=Lax 会在跨域同步时导致浏览器不发送该 Cookie,使 CouchDB 认为请求未认证,返回 401,从而阻断同步
解决思路:

  1. 同站化:让页面与 CouchDB 处于同一站点(子域名共享根域,或 nginx 反向代理到同域)。
  2. 修改 SameSite:在 local.ini 中设置
    [httpd]
    same_site = none
    [ssl]
    enable = true
    
    并强制全站 HTTPS,确保 Cookie 被浏览器接受。
  3. Token 替代方案:放弃 Cookie,改用 JWT 或 Basic Auth+_session 一次性令牌,在每次同步请求头里手动携带 Authorization,绕过 Cookie 策略。

拓展思考

  1. 如果企业内网仍使用 HTTP,SameSite=None 会被浏览器拒绝,此时只能采用同站代理或 Token 方案,无法依赖 Cookie。
  2. 在国内小程序生态里,Web-view 组件对 SameSite 的处理与系统浏览器一致,但小程序网络接口 wx.request 不受 Cookie 限制,可把同步逻辑挪到原生层规避该问题。
  3. 多租户 SaaS 场景下,每个租户分配独立子域(tenant-id.saas.cn),CouchDB 统一在 db.saas.cn,此时根域不同,即使反向代理也需解决证书 wildcard 成本,Token 方案反而更轻量
  4. 未来 Chrome 将逐步取消第三方 Cookie,但 SameSite 对“第一方”定义以可注册域为准,因此把页面和 API 放在同一根域下的子域方案仍长期有效,是国内金融、政务云落地时的首选架构。