ThinkPHP 6 的 Cookie 安全配置需在 config/app.php 的 'cookie' 数组中设置 secure 和 httponly;反向代理下须强制声明 HTTPS 或设 https=>true,且 samesite=None 时必须启用 secure。

ThinkPHP 6 中设置 Cookie 的 secure 和 httponly 参数在哪加
直接在 config/cache.php 或 config/cookie.php 里改不生效——ThinkPHP 6 的 Cookie 配置入口在 config/app.php 的 'cookie' => [...] 数组里。漏掉这层,哪怕控制器里手动 setcookie 也容易被覆盖。
实操建议:
- 打开
config/app.php,找到'cookie' => [...]块 - 确保包含
'secure' => true(仅 HTTPS 下发送)和'httponly' => true(JS 无法读取document.cookie) - 如果部署在反向代理后(如 Nginx + HTTPS 终止),必须同时设
'https' => true,否则secure会因框架检测不到 HTTPS 而自动降级
为什么 Cookie 在 HTTPS 环境下仍没带 Secure 标志
常见错误现象:浏览器 DevTools 显示 Cookie 缺少 Secure,但服务器明明开了 HTTPS。根本原因是 ThinkPHP 默认通过 $_SERVER['HTTPS'] 或 $_SERVER['REQUEST_SCHEME'] 判断协议,而反向代理常把请求转成 HTTP 再发给 PHP,导致检测失败。
解决办法:
立即学习“PHP免费学习笔记(深入)”;
- 在
public/index.php开头强制声明 HTTPS(比配置更早生效):if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } - 或在
config/app.php的cookie配置中显式写死:'secure' => true, 'httponly' => true, 'domain' => '.yourdomain.com'(注意domain前的点号,否则子域不共享) - 别依赖
Request::isSsl()动态判断——它和 Cookie 发送逻辑不同步
ThinkPHP 5.1 升级到 6.x 后 Cookie 安全配置失效
ThinkPHP 5.1 的 Cookie 配置分散在 config.php 的 'cookie' => [...],而 6.x 拆到了 config/app.php;更关键的是,5.1 默认 httponly 是 false,6.x 默认是 true,但 secure 在两个版本都默认 false,升级时容易只改了 httponly 却漏掉 secure。
参数差异要点:
- 5.1 的
'path'默认是'/',6.x 默认是request()->root()(可能变成/subpath/),影响 Cookie 作用域 - 6.x 新增
'samesite'选项(可选'Strict'、'Lax'、'None'),设为'Lax'能缓解 CSRF,但设'None'必须同时开secure - 调用
Cookie::set('name', 'val', $option)时,传入的$option会合并覆盖全局配置,但secure和httponly不会自动继承——必须显式传进去
调试时发现 JS 还能读到 Cookie,是不是 httponly 没起作用
不是配置没生效,而是你读的是服务端写入前就存在的旧 Cookie。浏览器不会因为新响应头设置了 HttpOnly 就立刻删掉旧的非 HttpOnly 版本。
排查步骤:
- 清空浏览器所有 Cookie(不只是当前域名),再刷新页面
- 检查响应头中
Set-Cookie字段是否含HttpOnly(注意大小写,必须是HttpOnly,不是httponly) - 在控制台执行
document.cookie,确认返回值里没有该 Cookie 名称(有则说明旧 Cookie 残留或配置未生效) - 如果用了前端框架(如 Vue)的 Cookie 库,注意它们可能绕过
HttpOnly直接读服务端接口——这不是 Cookie 本身的问题
samesite 与 secure 的绑定关系:设 samesite=None 却不配 secure,现代浏览器会直接丢弃该 Cookie。


















