编程 PHP 8.6 session 安全默认值变更:use_strict_mode、cookie_httponly、cookie_samesite 都改了

2026-10-10 21:02:48

PHP 8.6 session 安全默认值变更:use_strict_mode、cookie_httponly、cookie_samesite 都改了

PHP 8.6 的 UPGRADING 文件里,Session 部分有一组向后不兼容变更。核心是三个 INI 默认值转向安全侧,另加 NUL 字节校验、session_encode() 返回值、lazy_write 写入路径的调整。对应 RFC:session_security_defaults。

NUL 字节不再被静默接受

session.cookie_path、session.cookie_domain、session.cache_limiter 被设置为包含 NUL 字节的值时,现在会发出 warning,并且保持该设置不变。

之前的行为是静默接受:

  • cookie_path 和 cookie_domain 含 NUL 时,SAPI 会直接丢弃 Set-Cookie 头;
  • cache_limiter 含 NUL 时,值会在 NUL 字节处被静默截断。

另外,session_module_name() 的 $name 参数如果是含 NUL 字节的字符串,会抛出 ValueError。

session_encode() 对空会话返回空字符串

session_encode() 对空会话的返回值从 false 改为空字符串 ""。现在只有会话数据无法编码时才返回 false,主要出现在默认序列化 handler 下、某个 key 含有管道符 | 的情况。

依赖 === false 判断“会话为空”的代码需要改成判断 === ''。

lazy_write 下的空会话改为调用 updateTimestamp()

当 session.lazy_write 启用,且 session handler 实现了 SessionUpdateTimestampHandlerInterface 时:读取为空、写入时仍为空的会话,现在会触发 updateTimestamp() 而不是 write()。

之前空会话总是走 write(),因为 session_encode() 返回 false,绕过了 lazy_write 的比较逻辑。如果有自定义 handler 依赖“以空数据调用 write()”这个行为(例如借机销毁会话),需要把同样的逻辑放进 updateTimestamp():

public function updateTimestamp(string $id, string $data): bool
{
    if ($data === '') {
        return $this->destroy($id);
    }
    return $this->touch($id);
}

三个 INI 默认值改为安全值

session.use_strict_mode 默认 1

原值为 0。严格模式会拒绝未初始化的 session ID,用于缓解 session fixation。

受影响的是那些之前接受外部传入 ID、但存储中并不存在对应条目的自定义 handler。这类 handler 要么实现 validateId() / create_sid(),要么显式关闭严格模式:

ini_set('session.use_strict_mode', '0');

自定义 handler 侧需要能回答“这个 ID 是否存在”,以及自己生成新 ID:

public function validateId(string $id): bool
{
    return $this->storage->exists($id);
}

public function create_sid(): string
{
    return bin2hex(random_bytes(16));
}

session.cookie_httponly 默认 1

原值为 0。session cookie 不再能通过 JavaScript 的 document.cookie 读取。如果应用确实要从 JS 里读取 session cookie,需要显式关闭:

ini_set('session.cookie_httponly', '0');

session.cookie_samesite 默认 Lax

原值为未设置。session cookie 不再随跨站请求发送,只有使用安全 HTTP 方法的顶层导航是例外。依赖跨站 POST 提交携带 session cookie 的应用,需要显式设为 None,同时把 session.cookie_secure 设为 1:

ini_set('session.cookie_samesite', 'None');
ini_set('session.cookie_secure', '1');

php.ini 里对应写法:

session.use_strict_mode=0
session.cookie_httponly=0
session.cookie_samesite=None
session.cookie_secure=1

SessionHandler::validateId()

新增了 SessionHandler::validateId(),它委托给当前配置的 save handler。

两点子类相关行为:

  • 子类声明 validateId() 时如果没写返回类型,会触发 tentative bool 返回类型带来的 deprecation notice;
  • 子类覆盖 open() 且没有调用 parent::open() 时,保持原有行为,并在 ID 被验证时发出 warning。
复制全文 生成海报 PHP Session 安全

推荐文章

程序员茄子在线接单