必须禁用files驱动,因其明文存储、无加密签名,易被读取篡改;启用redis需严格配置host/port/database/timeout等参数,并手动设置cookie_secure、httponly、use_strict_mode等安全选项。

ThinkPHP 生产环境必须禁用 files 会话驱动,否则 session 文件明文落盘、无签名、无加密,攻击者只要能读取临时目录(比如通过共享主机或配置失误),就能直接伪造登录态。
为什么不能留着 session.type = file
ThinkPHP 默认用 files 驱动,底层就是 PHP 原生的 session.save_handler = files。它把 $_SESSION 序列化后写进 runtime/session/ 或系统 /tmp,内容完全明文:
- 没加密:改
user_id字段就能越权访问他人账户 - 没签名:无法校验数据是否被篡改
- 权限难控:很多部署环境里 web 进程对
/tmp可读,甚至其他用户也能 ls 出来 - 静默降级:就算你配了 Redis,但扩展没装或参数错,TP 会悄悄 fallback 回 file,日志还不报
session.type = redis 的硬性前提
不是改个配置就完事。ThinkPHP 的 Redis 会话依赖 phpredis 扩展(不是 Predis),且参数缺失或类型错误会导致连接失败、数据乱码、或直接退化到 file。
- 运行
php -m | grep redis确认已加载redis模块(不是redis.so被注释) -
session.redis.host和session.redis.port必须显式配置,不能靠默认值 -
session.redis.password即使为空,也得设为null或空字符串'',否则底层初始化失败 - 别用 DB 0:
session.redis.database = 2,避免被运维误执行FLUSHDB清空全部会话 - 加超时:
session.redis.timeout = 60,不然 Redis 暂不可用时,请求会卡满整个 PHP 超时时间
Cookie 安全参数必须手动补全
ThinkPHP 的 session.encrypt 只加密 session 数据体,不保护 Cookie 本身。如果没关掉 session.cookie_secure 或漏设 SameSite,中间人照样能劫持 ID 复用。
- HTTPS 环境下,
session.cookie_secure = 1必须开启,否则浏览器拒绝发送带Secure标志的 Cookie -
session.cookie_samesite = Lax(别设None),老版 IE 和部分安卓 WebView 不支持None,设了反而失效 -
session.use_strict_mode = 1是防会话固定的底线,没它,攻击者发一个预生成的 PHPSESSID 链接就能固定你的会话 -
session.use_trans_sid = 0必须关闭,否则 URL 里带?PHPSESSID=xxx,加密等于白做 -
session.cookie_httponly = 1要开,防 XSS 窃取 Cookie(哪怕 JS 拿不到,也要防绕过)
session.encrypt_key 长度和登录后刷新 ID
ThinkPHP 的 AES 加密要求密钥严格 32 字节,短了会静默失败;而仅加密不刷新 ID,仍可能被会话固定攻击利用。
- 用
bin2hex(random_bytes(32))生成密钥,别手敲或截断 - 用户成功登录后,必须调用
session_regenerate_id(true),销毁旧 session 并生成新 ID —— ThinkPHP 的Session::regenerate()就是封装这个 - 别只依赖 IP 绑定:移动网络、NAT 环境下 IP 易变,硬校验反而导致合法用户频繁掉线
- Redis 存储本身不解决重放问题,
session.id_length建议设为 48(而非默认 32),配合use_strict_mode提高 ID 猜解门槛
最易被忽略的是:Redis 配置写错时 TP 不报错,而是默默切回 file;还有就是 session.cookie_secure 在本地 HTTP 开发时必须关,上线又必须开,这个开关经常被遗忘在 config 文件里,结果 HTTPS 站点收不到 Cookie。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











