PHP会话安全需手动配置session.cookie_secure、session.cookie_httponly、session.use_only_cookies和session.use_trans_sid=0,并在session_start()前调用ini_set;登录后必须执行session_regenerate_id(true)防会话固定。

PHP 默认的 session_start() 不做任何安全加固,直接用等于裸奔——会话 ID 明文传、JS 可读、URL 里乱跑、登录前后 ID 不变,攻击者拿到一个 PHPSESSID 就能冒充用户进后台。
session.cookie_secure 和 session.cookie_httponly 必须手动设
ThinkPHP、Laravel 等框架都不会自动开启这两个关键开关。不设 session.cookie_secure,HTTPS 下 Cookie 仍可能被降级到 HTTP 发送;不设 session.cookie_httponly,XSS 成功后 JS 就能直接读走 PHPSESSID。
必须在 session_start() 之前调用:
ini_set('session.cookie_secure', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.use_only_cookies', '1');
- 开发环境没配 HTTPS?别硬开
session.cookie_secure,否则 Cookie 根本不发,登录必失败 -
session.use_only_cookies = 1要同步设,否则浏览器 fallback 到 URL 参数传 ID,?PHPSESSID=xxx会出现在日志、Referer、代理缓存里 - 这些
ini_set()必须放在入口文件(如index.php或中间件最开头),晚于session_start()就无效
登录成功后必须调用 session_regenerate_id(true)
这是防会话固定(Session Fixation)的刚性动作。攻击者提前构造带固定 ID 的登录链接(比如 login.php?PHPSESSID=attacker123),用户一登录,就直接沿用这个 ID,攻击者立刻接管会话。
立即学习“PHP免费学习笔记(深入)”;
正确写法(在认证通过、写入用户数据前执行):
if ($login_success) {
session_regenerate_id(true); // true 表示删除旧 session 文件
$_SESSION['uid'] = $user['id'];
$_SESSION['login_time'] = time();
}
- 漏掉
true参数,旧 session 文件还在磁盘上,攻击者拿着旧 ID 仍能读取会话数据 - 别用
Session::clear()或$_SESSION = []替代——它们只清内容,不换 ID - 敏感操作(改密、删账号)也建议再 regenerate 一次,不是只限登录
禁用 trans_sid 防止 URL 泄露 Session ID
PHP 默认可能开启 session.use_trans_sid,一旦启用,所有相对链接(如 /user/profile)都会被自动补上 ?PHPSESSID=xxx。这种泄露路径极难审计,且无法靠前端过滤清除。
必须显式关闭:
ini_set('session.use_trans_sid', '0');
- 该设置必须在
session_start()前生效,ThinkPHP 的Session::init()不会帮你覆盖 PHP ini 配置 - 检查是否已开:输出
ini_get('session.use_trans_sid'),返回"1"就危险 - 配合
session.use_only_cookies = 1使用,双重保险
IP 绑定慎用,User-Agent 校验意义有限
有人一上来就想把 $_SERVER['REMOTE_ADDR'] 写进 session 并每次比对,但现实是:NAT 网关、移动网络出口 IP 频繁变化,CDN 回源地址可能统一,一绑就误杀合法用户。
User-Agent 更不可靠——它可被任意伪造,且浏览器升级、插件变更都会触发变动。
- 真要加设备指纹,优先考虑组合字段(如 UA + 屏幕分辨率 + 时区 + WebGL 渲染指纹),但依然不能替代 HTTPS + Secure+HttpOnly + regenerate_id
- IP 校验若必须上,建议只用于高危操作二次确认(如转账页弹窗提示“检测到新设备”,而非直接拦截)
- 最易被忽略的是:所有校验逻辑必须放在 session 启动之后、业务逻辑之前,且不能依赖未过滤的
$_SERVER值
真正起效的防护是层层叠加:HTTPS 是底线,Secure+HttpOnly 是 Cookie 基线,use_only_cookies 和 use_trans_sid=0 切断 URL 泄露路径,session_regenerate_id(true) 打断固定攻击链——少其中一环,防御就出现可利用缺口。



















