php 8.3 中防御 sql 注入需同时满足三条件:禁用模拟预处理(pdo::attr_emulate_prepares => false)、所有用户输入严格使用占位符、连接字符集设为 utf8mb4;缺一不可。

PHP 8.3 中仅调用 PDO::prepare() 不足以防御 SQL 注入——必须显式关闭模拟预处理、所有用户输入进占位符、字符集设为 utf8mb4,三者缺一不可。
为什么 PDO::ATTR_EMULATE_PREPARES => false 是硬性前提
PHP 8.3 默认仍启用模拟预处理(PDO::ATTR_EMULATE_PREPARES => true),此时 prepare() 仅在 PHP 层做字符串替换,根本没发往 MySQL 服务端编译。攻击者传入 id=1%00 OR 1=1 或 status=0; DROP TABLE users; 仍可能触发服务端解析执行。
显式禁用后,若 MySQL 版本低于 5.1.17(极罕见),会抛出 PDOException——这不是 bug,是强制你升级数据库的信号。
连接时必须这样写:
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
]);
所有用户输入都得进占位符,包括数字和布尔值
“整数不用防”是最大误区。(int)$_GET['id'] 强转后拼进 SQL:"WHERE id = " . (int)$_GET['id'],遇到 UTF-8 变体或宽字节截断仍可能绕过;而预处理能严格隔离数据类型与语法上下文。
- 错误写法:
$sql = "SELECT * FROM orders WHERE user_id = " . $_GET['id']; - 正确写法(命名占位符):
$stmt = $pdo->prepare("SELECT * FROM orders WHERE user_id = :uid AND paid = :paid"); - 绑定时指定类型更稳妥:
$stmt->bindValue(':paid', (bool)$_GET['paid'], PDO::PARAM_BOOL); - 问号占位符也安全:
$stmt->execute([$_GET['id'], (bool)$_GET['paid']]);
LIKE 查询的通配符必须在 PHP 层加,不能塞进 SQL 字符串
WHERE name LIKE ?% 或 "%{$_GET['q']}%" 是典型错误——占位符只包裹值,不控制其在 SQL 中的位置或语义。用户传入 q=admin%27 OR %271%27=%271 就会直接拼进查询。
正确做法分三步:
- 先清理通配符特殊字符:
$q = str_replace(['%', '_'], ['\%', '\_'], $_GET['q'] ?? ''); - 再手动加前后缀:
$search = '%' . $q . '%'; - 最后绑定,并在 SQL 中声明 ESCAPE:
WHERE name LIKE ? ESCAPE '\'
执行:$stmt->execute([$search]);
表名、字段名、ORDER BY 等结构化部分必须白名单校验
占位符无法用于表名、列名、ORDER BY 子句或 UNION 关键字——这些属于 SQL 结构,不是数据。PDO 绑定机制对此完全无效。
必须用白名单硬编码或校验:
- 错误:
$sql = "SELECT * FROM {$_GET['table']} WHERE ..."; - 正确:
$allowed_tables = ['users', 'orders', 'products']; $table = in_array($_GET['table'], $allowed_tables) ? $_GET['table'] : 'users'; -
ORDER BY同理:$allowed_sorts = ['created_at', 'name', 'price']; $sort = in_array($_GET['sort'], $allowed_sorts) ? $_GET['sort'] : 'created_at'; $sql = "SELECT * FROM users ORDER BY $sort";
这类校验一旦漏掉,前面所有预处理努力都会被绕过——这是最常被忽略、也最致命的一环。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











