SQL注入必然可利用,必须用禁用模拟预处理的PDO预处理语句,占位符仅限?或命名参数,输入需验证清洗,输出需htmlspecialchars,操作后须PRG重定向。

直接用 $_POST 拼 SQL 就是高危操作
只要出现类似 "INSERT INTO users VALUES ('" . $_POST['username'] . "', ...)" 这种字符串拼接,就等于把数据库大门钥匙交给了用户。SQL注入不是“可能被利用”,而是“必然可利用”——攻击者只需在表单里填 ' OR '1'='1 或更复杂的 payload,就能绕过登录、拖库甚至删表。
必须用预处理语句,且禁用模拟准备(PDO::ATTR_EMULATE_PREPARES = false)
预处理不是加个 prepare() 就万事大吉。PDO 默认开启模拟预处理(emulate prepares),它只是 PHP 层做转义,不发给 MySQL 真正的 prepare 流程,宽字节或特殊编码下仍可能被绕过。
- 连接时必须显式关闭:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false) - 占位符只能是
?或命名参数如:email,不能拼进字段名、表名、排序方向 -
LIKE查询中的通配符要由 PHP 拼好再传入,比如:$search = '%' . $_POST['q'] . '%'; $stmt->execute([$search]);
输入验证和清洗不能省,但目的不是“替预处理兜底”
filter_var() 和 htmlspecialchars() 不是用来补救 SQL 拼接漏洞的,它们解决的是另一类问题:XSS 和脏数据入库。即使用了预处理,仍需:
- 对邮箱用
filter_var($email, FILTER_VALIDATE_EMAIL),对数字用FILTER_VALIDATE_INT带范围选项 - 用户名等文本字段用白名单正则,例如
preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username) - 输出到 HTML 前一律过
htmlspecialchars($data, ENT_QUOTES, 'UTF-8'),别信“我只存安全数据” - 绝不直接用
$_POST['field']做任何事,先赋值、再验证、再清洗、最后绑定
重定向(PRG)不是防注入,但能拦住重复提交引发的连锁风险
防注入靠的是数据与逻辑分离,而 PRG(Post-Redirect-Get)解决的是用户刷新导致的二次执行问题。没做重定向的话,哪怕 SQL 是安全的,也可能因重复插入触发业务异常(比如两次发优惠券、两次扣库存)。
立即学习“PHP免费学习笔记(深入)”;
成功处理后必须用:header('Location: success.php'); + exit;。注意:header() 前不能有任何输出(包括空格、BOM、echo),否则会失败并继续执行后续代码——这个细节常被忽略,导致重定向形同虚设。



















