SameSite Cookie 兼容性降级
解读
国内业务往往要兼顾“老微信内置浏览器、支付宝内嵌 WebView、各大安卓厂商系统浏览器”三类顽固旧环境,它们对 2019 年之后 IETF 草案里 SameSite=None; Secure 这一对标记的支持参差不齐:
- 部分 Chromium 53~65 内核直接把 SameSite=None 当成 Strict 处理;
- iOS 9-11 的 UIWebView 不认识 SameSite,导致带标记的 Cookie 被直接丢弃;
- 某些网关(阿里 MGS、腾讯 TGW)在 HTTPS 卸载后忘记把 Secure 标记原样透传,结果 SameSite=None; Secure 被浏览器判定为非法。
一旦写错,用户会出现“登录态频繁丢失、支付回调无法写 Cookie、H5 活动页反复跳转授权”等线上事故。面试官问“兼容性降级”,实质考察:
- 能否准确识别 User-Agent 中的“问题内核”;
- 能否在 PHP 层给出“可灰度、可回滚、零业务侵入”的降级策略;
- 是否理解 Cookie 与 Session 生命周期、CSRF 防护的耦合关系。
知识点
- setcookie 函数签名:setcookie(value, path, secure, options(PHP 7.3+)才支持 array['samesite'];
- 在 7.2 及以下需手动拼 header('Set-Cookie: ...');
- SameSite 三值含义:Strict=完全禁止跨站发送,Lax=允许顶级导航 GET,None=任意跨站;
- 浏览器嗅探:Chromium 51-66 黑名单 + UC/QQ 浏览器特殊 UA;
- 安全侧:降级到 Lax 时必须同步调整 CSRF Token 的二次校验逻辑,否则旧浏览器反而更容易被攻击;
- 灰度手段:基于 Cookie 的 A/B 版本号或 ConfCenter 配置,实时切换 SameSite 值;
- 监控指标:Cookie 写入成功率、鉴权失败率、前端埋点上报“SameSite 异常”事件。
答案
线上 PHP 7.2 环境,封装统一 Cookie 管理类,兼容降级思路如下:
- 先定义“问题浏览器”正则:
_SERVER['HTTP_USER_AGENT']); - 配置中心读取开关:
$cfg = \Config::get('cookie.samesite_policy'); // off = 不发送 SameSite,lax = Lax,none = None - 拼装 Set-Cookie 头:
if (PHP_VERSION_ID >= 70300) {
expire, 'path' => domain,
'secure' => true, 'httponly' => true, 'samesite' => ''];
if (cfg === 'none' && !broken) {
options['samesite'] = 'None'; } elseif (cfg === 'lax') {
options['samesite'] = 'Lax'; } setcookie(name, options);
} else {
cfg === 'none' && !broken) { same = '; SameSite=None';
} elseif (cfg === 'lax') { same = '; SameSite=Lax';
}
header(sprintf('Set-Cookie: %s=%s; expires=%s; Max-Age=%d; path=%s; domain=%s; secure; httponly%s',
value), gmdate('D, d-M-Y H:i:s T', expire - time(), domain, $same), false);
} - 灰度回滚:
若监控发现某类 UA 的登录失败率突增 >1%,ConfCenter 一键把 samesite_policy 改为 lax 或 off,无需发版; - CSRF 补偿:
旧浏览器走 Lax 时,POST/PUT 请求必须带双重 Token(Header + Form),后端中间件统一校验。
通过上述方案,可在 30 分钟内完成全量降级,保证双十一等高并发节点 0 回滚。
拓展思考
- 如果业务同时提供 302 短链跳转广告,Lax 级 Cookie 在跨站 POST 场景下仍会被浏览器拦截,是否考虑把关键标识下沉到 URL 加密参数?如何防止参数被篡改?
- 在 HTTP/3 全面普及后,QUIC 层 0-RTT 早期数据复用可能再次绕过 SameSite,PHP 端如何与 CDN 配合,对早期数据请求强制二次鉴权?
- 国内小程序 web-view 组件即将全面禁止第三方 Cookie,未来 PHP 服务端是否需要把 Session 体系彻底改造成“无 Cookie + JWT + 刷新令牌”?灰度策略如何设计?