PHP 8.6 三个 session 默认值转向安全:升级前先查这三处,Lax 会让跨站 POST 丢 session
PHP 8.6 把三个 session 相关配置的默认值改成了安全方向:
session.use_strict_mode默认1session.cookie_httponly默认1session.cookie_samesite默认Lax
它们各自都在防一类攻击,但也各自能让一个正常跑着的应用在升级后出问题。PHP 8.6 GA 日期是 2026-11-19。
session.use_strict_mode = 1
解决什么:session fixation。应用没有生成过的 session id,PHP 直接拒绝,攻击者无法把一个自己已知的 id 塞给受害者然后复用同一个会话。
可能打断什么:任何依赖外部传入 session id 的流程。id 从 URL 参数、隐藏表单字段、网关 header 透传进来时,PHP 在自己的存储里没见过这个 id,就丢弃并重新生成一个。表现是用户"莫名其妙掉登录"、购物车清空、多标签页互相踢掉。自己实现的 session handler 也要确认能正确回答"这个 id 是否存在",否则所有 id 都会被判为不存在。
session.cookie_httponly = 1
解决什么:XSS 直接读 document.cookie 拿走 session id。设上之后 JS 读不到这个 cookie。
可能打断什么:所有在前端读 session cookie 的 JavaScript。常见的有:把 session id 塞进 fetch/XHR 请求头的前端代码、前端自己解析登录态的老逻辑、部分 SDK 和埋点脚本。document.cookie 里不再出现那个名字,代码不会报错,只会静默失效,通常表现为 401 或页面显示未登录。
session.cookie_samesite = Lax
解决什么:跨站请求默认不带 session cookie,缓解 CSRF。Lax 只允许顶层导航的 GET 请求携带 cookie。
可能打断什么:所有以 POST 形式从别的站点回到你站点的入口。
- SSO:IdP 认证完成后 POST 回你的回调地址,此时没有 session cookie。
- 支付回调:第三方支付网关 POST 到你的
notify/return地址,同样拿不到 session。
典型症状是回调里 $_SESSION 为空、CSRF token 校验失败、订单状态没被更新。GET 形式的跳转不受影响,出问题的都是 POST。
升级前逐个自查
- 搜索代码里有没有从请求读 session id 的地方:
$_GET['PHPSESSID']、$_POST[session_name()]、自定义 header,以及框架在 session 启动前使用外部传入 id 的逻辑。 - 确认前端 JS 是否读过 session cookie。直接搜 cookie 解析代码,别只看 localStorage。
- 列出所有跨站回来的入口:SSO 回调、支付 notify、OAuth redirect、webhook,看它们是 POST 还是 GET。
- 在 staging 上先把这三个默认值打开,跑一遍登录、支付、SSO 全流程,再动生产。
回退与兼容
三个开关可以分开回退,默认值只在没有显式配置时生效,显式写回旧值仍然有效:
session.use_strict_mode = 0
session.cookie_httponly = 0
session.cookie_samesite =
也可以只对特定路径用 ini_set 局部覆盖。
- SameSite:跨站 POST 回调如果必须带 cookie,改成
SameSite=None; Secure(需要 HTTPS);或者把回调改成顶层 GET 导航;或者回调路径干脆不依赖 session,改用签名的 token 校验来源。 - httponly:正解是把前端需要的值放到单独的、非 httponly 的 cookie 或接口响应里,而不是把 session id 交给 JS。
- strict_mode:删掉手动
session_id()设置外部 id 的路径,改成由应用先生成 session 再下发。
来源: