编程 PHP 8.6 把三个 session 默认值改严了:原生 session 老站的升级排查

2026-11-15 21:01:54

PHP 8.6 把三个 session 默认值改严了:原生 session 老站的升级排查

PHP 8.6 定在 2026-11-19 发布。这个版本调整了几个 php.ini 里与 session 相关的默认值,方向都是让新装环境默认更安全:

配置项旧默认值新默认值
session.use_strict_mode01
session.cookie_httponly01
session.cookie_samesite未设置Lax

前提先说清楚:这三个改动只影响新安装的默认值。如果机器上已经有 php.ini,升级到 8.6 时不会去改你现有的配置,这些值保持原样不动。所以它更接近「新环境开箱即严」,不是「升级即故障」。

另外,Laravel 自己管理 session cookie,走框架这套的站点基本不受影响。受影响的是直接用原生 PHP session、并且依赖旧默认值行为的代码。相关讨论在 session defaults RFC 里。

session.use_strict_mode:0 → 1

打开后,服务端不再接受客户端传来的、自己没见过的 session id。session_start() 遇到一个未在存储中登记的 id,会直接生成新 id,而不是沿用客户端给的那个。这是防会话固定的核心手段:攻击者没法把自己准备好的 SID 塞给受害者然后共用会话。

会踩到的场景有两类:

  • 外部系统预置 SID。比如单点登录跳转时由另一个应用写 cookie 或拼 URL 把 session id 传进来,PHP 这边 session_start() 一读,发现这个 id 不存在,直接丢掉重建,握手就断了。
  • 自己写 session_id() 但不 regenerate。代码里先 session_id($sid) 再 session_start(),指望接管某个会话;strict mode 下这个 id 只要不在存储里就不作数。正确做法是启动后立刻 session_regenerate_id(true),让服务端自己签发。

session.cookie_httponly:0 → 1

PHPSESSID 这个 cookie 会带上 HttpOnly 属性,JavaScript 通过 document.cookie 读不到它。

踩坑的通常是老前端:页面里有段 JS 直接读 session cookie 拼请求参数,或者第三方统计/客服脚本依赖这个值。表现很直接——document.cookie 里找不到 PHPSESSID,读到 null 或 undefined,但后端会话其实是正常的。

session.cookie_samesite:未设置 → Lax

以前不带 SameSite 属性,浏览器按自己的策略走;现在明确标 Lax。区别在于跨站请求会不会带上这个 cookie:

  • 跨站顶层 GET 导航(点链接、302 跳过去):带 cookie,正常。
  • 跨站顶层 POST(别的域的表单直接 POST 到你站,SSO 里 IdP 回传 SAMLResponse 就是典型):不带 cookie。
  • 跨站 iframe 里的请求,包括 iframe 内的表单提交和加载:不带 cookie。

后两种的表现是:请求进来时 session 是全新的,登录态丢失,或者 CSRF token 校验失败。如果业务上确实需要跨站 POST 保持会话,那得用 SameSite=None,并且必须同时是 Secure,也就是只能跑在 HTTPS 上。

排查顺序

按症状走,比逐个配置猜要快:

  1. 先确认环境确实是新默认值:php -i | grep -i session 看三项的实际取值,同时确认这是新装环境还是从旧版本升上来的(升级的话这几项根本不会变)。
  2. 登录后立刻掉登录、每次请求都是新 session:先看 session.cookie_samesite,再看 session.use_strict_mode。跨站 POST 回跳的场景优先怀疑 SameSite。
  3. 前端读不到 session cookie:session.cookie_httponly。
  4. session_id() 设了不生效、会话接不上:session.use_strict_mode。

兼容写法

确认是默认值导致的问题后,两条路:改配置,或者代码里显式覆盖。

改配置(php.ini,或 FPM pool 里的 php_admin_value、.htaccess 里的 php_value):

session.use_strict_mode = 0
session.cookie_httponly = 0
session.cookie_samesite =

代码里覆盖,必须在 session_start() 之前执行:

ini_set('session.use_strict_mode', '0');
ini_set('session.cookie_httponly', '0');
ini_set('session.cookie_samesite', '');   // 空串 = 不输出该属性

session.cookie_samesite 置空串是不发这个属性,不是发 None。

能不改就别改。cookie_httponly 和 use_strict_mode 的默认值变严基本只会暴露本来就该修的老代码;确实要保留旧行为时,优先用 ini_set 在具体入口文件里局部放开,而不是全局改 php.ini,免得新代码也跟着松掉。

复制全文 生成海报 PHP 会话 升级

推荐文章

程序员茄子在线接单