登录前后抓包,Cookie 里的 PHPSESSID 完全没变。把登录前那个 ID 发给同事,他打开就是已登录状态。日志里能对上时间点,这种反而好排。
登录成功只写了 $_SESSION['uid'],没有调用 session_regenerate_id。攻击者先把固定 ID 送到受害者浏览器,等对方登录,这个 ID 直接变成有效会话。这一点先确认清楚,后面就不用反复试。
session_start(); // 校验通过后 session_regenerate_id(true); $_SESSION['uid'] = $uid;
这次卡住的地方就在「会话固定」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。
处理上按这个顺序:登录校验通过后立刻 session_regenerate_id(true),旧会话文件一并删掉;Cookie 补上 HttpOnly 和 SameSite=Lax,脚本读不到;退出登录先 session_destroy 再清 Cookie。
结果对不对很好判断,再抓一次包,登录后 PHPSESSID 已经换成新值,旧 ID 访问变回未登录。
