跳转到主内容
极星编程网:以代码为星,赴技术山海!

php怎么防止csrf攻击_php如何生成验证token防御跨站请求

最可靠的PHP CSRF防护是用session_regenerate_id(true)重置会话并存token于$_SESSION['csrf_token'],生成用bin2hex(random_bytes(32)),表单以htmlspecialchars处理的hidden字段传递,校验用hash_equals(),失效时静默拒绝。 PHP 中用
session_regenerate_id()
配合
$_SESSION
存 token 最可靠 CSRF 的核心是攻击者能预测或复用你的请求凭证,所以关键不是“生成 token”,而是让 token 具备会话绑定、一次性、时效性。PHP 原生不自带 CSRF token 函数,得自己搭骨架。
session_regenerate_id()
不只是防 session fixation,它重置 session ID 的同时,也帮你清掉旧会话里可能被窃取的 token 状态。 每次用户登录或权限变更后必须调用
session_regenerate_id(true)
(
true
表示删除旧 session 文件) token 存进
$_SESSION['csrf_token']
,别存 cookie 或前端 localStorage 生成用
bin2hex(random_bytes(32))
,别用
md5(time().rand())
这种可预测组合 表单提交后立即验证并重置:验证通过就
unset($_SESSION['csrf_token'])
,防止重放 Form 提交时怎么传 token 才不被绕过 很多人把 token 放在 URL 参数里,或者藏在 JS 变量中,结果被 XSS 一抓一个准。真正安全的传法只有一种:作为隐藏字段,且和服务端存储的完全一致。 必须用
,
htmlspecialchars()
防止属性注入 不要用 JS 动态填充 value,避免 DOM XSS 污染值 如果页面有多个 form(比如编辑+删除按钮),每个都得用独立 token,或统一用同一个但校验后立即失效 AJAX 请求需从 DOM 读取 hidden 字段值,别从全局变量或 API 接口单独取——那等于暴露 token 获取通道
hash_equals()
校验 token 是必须的,不是可选 直接用
==
或
===
比较 token 会触发时序攻击。攻击者靠响应时间差异就能暴力猜出 token 字符,尤其当 token 是 hex 字符串时更明显。 校验必须写成
hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')
两边都不能为空字符串,否则
hash_equals()
会返回
false
,但你要先确保 key 存在,而不是让它崩在 undefined index 如果 token 已被 unset,直接拒绝,不给任何提示信息(连 HTTP 状态都别用 403,统一用 400 或重定向到错误页) CSRF token 在多标签页或长页面中容易失效的几个现实问题 用户开两个 tab 同时操作,或者页面挂了半小时再提交,token 就大概率失效。这不是 bug,是设计使然,但体验要兜住。 PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 立即学习 “ PHP免费学习笔记(深入) ”; session 生命周期别设太短(比如
ini_set('session.gc_maxlifetime', 1440)
是底线) 表单页加载时检查
$_SESSION['csrf_token']
是否存在,没有就现场生成一个并写入 session,别等提交才报错 AJAX 表单可加个前置请求
/api/csrf-token
刷新 token,但该接口本身也要受 CSRF 保护(比如只允许 POST + referer 白名单) 别在 JS 里自动重试失败的提交——token 失效后重试只会反复失败,应提示用户刷新页面 最麻烦的其实是前后端分离场景:PHP 只管发 token,但前端可能缓存、复用、跨域丢 header。这时候 token 必须和 session ID 强绑定,且不能依赖客户端传来的 session_id cookie 做校验——得用服务端存储的 session 数据反查,否则换 cookie 就绕过了。

相关文章