表单同时开了跨站请求校验和验证码,第一次提交提示验证码错误,第二次再提交变成「页面已过期」,用户怎么试都过不去。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

$_SESSION['csrf_token']  // 校验只读不删
$_SESSION['captcha_code'] // 通过后再 unset

两个校验都从会话里取值并删除,第一个校验失败时已经把令牌消费掉,第二次请求拿不到有效令牌。中间件顺序也不对。这一点先确认清楚,后面就不用反复试。

「CSRF 验证码冲突」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

具体做法是,把两个校验拆开,各自用独立的会话键,互不消费;校验失败不要删除令牌,只有全部通过才清;按固定顺序执行跨站校验再验证码,失败时返回具体是哪一项。

改完照着核一遍,验证码填错后重新提交,提示仍是验证码错误,不会变成页面过期。

作者 9823189