PHP防CSRF最可靠做法是CSRF Token配合会话验证与SameSite Cookie:Token须用random_bytes(32)生成并存于$_SESSION,表单中用htmlspecialchars()输出隐藏字段,服务端用hash_equals()校验并立即失效,同时设置SameSite=Lax增强防护。

PHP防跨站请求伪造(CSRF),核心是确认请求确实来自用户本人的操作,而不是被恶意网站诱导发出的。最可靠、最通用的做法是用CSRF Token配合会话验证,再辅以浏览器层面的SameSite Cookie机制。
生成并绑定一次性Token
Token必须和当前用户会话强绑定,且不可预测、不可重用。不能靠时间戳或rand()拼接,得用加密安全的随机源:
- 用
random_bytes(32)生成原始字节,再转成十六进制字符串(如bin2hex(random_bytes(32))) - 存入
$_SESSION['csrf_token'],别存在Cookie或前端存储里 - 每次打开新表单页时检查是否存在,不存在就生成;不强制每页都刷新,但敏感操作前建议校验时效性
在表单中正确嵌入Token
Token要作为隐藏字段,随表单一起提交,且输出时需防XSS污染:
- HTML中写:
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES | ENT_HTML5, 'UTF-8'); ?>"> - 务必用
htmlspecialchars()转义,否则攻击者可能通过XSS窃取Token,让CSRF防护失效 - 所有涉及状态变更的请求(POST/PUT/DELETE)都要加,不只是登录或转账,还包括删评论、改邮箱等
服务端严格验证并及时失效
验证不是简单比对字符串,而是要防时序攻击、防重放、防跨会话冒用:
立即学习“PHP免费学习笔记(深入)”;
- 收到请求后,先检查
$_POST['csrf_token']是否存在,再检查$_SESSION['csrf_token']是否匹配 - 比对必须用
hash_equals(),不用===,避免时序侧信道泄露 - 验证通过后,立即
unset($_SESSION['csrf_token'])或生成新Token替换旧值,防止重复提交 - 不要只验证POST,AJAX请求同样要传Token(例如放在请求头
X-CSRF-TOKEN或请求体里)
叠加SameSite Cookie增强边界防护
SameSite属性能限制第三方站点发起带Cookie的请求,虽不能替代Token,但可作为纵深防御的一环:
- 设置Cookie时加上
SameSite=Lax(兼容性好,覆盖大多数GET/POST场景)或SameSite=Strict(防护更强,但可能影响跳转体验) - PHP中可通过
session_set_cookie_params(['samesite' => 'Lax'])或setcookie()的samesite参数配置 - 注意:IE和旧版浏览器不支持SameSite,不能单独依赖它防CSRF



















