PHP安全需严格转义用户数据、使用CSRF token、重验敏感操作身份、禁用拼接SQL并采用预处理语句。

PHP输出时必须对用户数据做htmlspecialchars()转义
不转义直接echo $_GET['q']或echo $user_input,等于把XSS入口焊死在页面上。浏览器会把未转义的<script>alert(1)</script>当真实脚本执行。
关键点:
-
htmlspecialchars()必须显式指定ENT_QUOTES和UTF-8编码,否则可能绕过:htmlspecialchars($input, ENT_QUOTES, 'UTF-8') - 仅适用于HTML普通文本上下文;如果插在
<script></script>内、href属性或CSS中,需用对应上下文的防护(如JSON编码+json_encode()、urlencode()) - 不要依赖
htmlentities()或自定义正则过滤——它们漏报率高,且无法覆盖新出现的绕过方式
表单提交必须校验CSRF token且绑定用户会话
攻击者伪造一个指向/delete.php?id=123的图片链接,用户点击即触发删除——这就是典型CSRF。防御核心不是“禁止跨域”,而是证明请求来自当前用户的真实操作。
实操要点:
- 生成token时用
bin2hex(random_bytes(32)),存入$_SESSION['csrf_token'],同时输出到表单隐藏域: - 服务端验证必须严格比对:
if (!hash_equals($_SESSION['csrf_token'], $_POST['token'])) { die('Invalid CSRF token'); }(注意用hash_equals()防时序攻击) - token不能复用:每次提交后立即重置
$_SESSION['csrf_token'],或使用一次性token(提交即失效) - 不要把token放URL里(易被日志/Referer泄露),也不要用
$_SERVER['HTTP_REFERER']校验(不可靠、可伪造)
敏感操作必须重新验证用户身份,不能只靠session存在
用户登录后,$_SESSION['logged_in'] = true能维持状态,但不能代替权限再确认。比如修改密码、转账、删账号等操作,必须要求输入当前密码或二次认证。
常见疏漏:
- 仅检查
isset($_SESSION['user_id'])就执行高危操作 - token过期时间设为数天甚至永久,没做活跃度检测
- 忘记清理session:用户登出后没调用
session_destroy()和setcookie(session_name(), '', time()-3600) - 敏感接口未做IP/设备指纹绑定,导致session劫持后可长期滥用
数据库查询必须用预处理语句,禁用字符串拼接
哪怕只是"SELECT * FROM users WHERE id = " . $_GET['id'],也足以让攻击者注入1 OR 1=1拖库。这不是“加个intval()就能解决”的问题。
正确做法:
- 所有动态参数走PDO预处理:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$_GET['id']]); - 避免用
mysqli_real_escape_string()——它只对单引号转义,对数字上下文无效,且易被宽字节注入绕过 - 不要信任任何用户输入:即使前端做了限制,后端仍要按不可信数据处理
- 数据库连接必须设置
PDO::ATTR_EMULATE_PREPARES => false,否则PDO可能退化为模拟预处理,失去防护能力
真正难的不是记住这些规则,而是每处echo、每个$_POST、每次query都条件反射式地停下来想:“这里有没有上下文?有没有会话状态?有没有用户可控输入?”——漏掉一次,防线就塌了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











