最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
PHP项目中自定义查询类如何防SQL注入?
时间:2026-07-09 10:18:02 编辑:袖梨 来源:一聚教程网
自定义SQL查询类必须强制走预处理绑定路径,禁止字符串拼接;所有用户输入参数须通过占位符传入,动态表名/字段名需白名单校验,IN语句要手动展开占位符,输入验证不能替代预处理。
直接用字符串拼接构建 SQL 的自定义查询类,哪怕加了 addslashes() 或 mysqli_real_escape_string(),也挡不住 SQL 注入——这不是加固问题,是架构缺陷。
自定义查询类必须强制走预处理绑定路径
很多团队写所谓“通用查询类”,底层仍用 mysql_query() 或 mysqli_query() 拼接字符串,再套一层方法名包装,本质没变。真正安全的自定义类,所有执行入口(如 select()、update())内部必须调用 prepare() + execute(),且禁止开放原始 SQL 拼接接口。
- 类构造时就要持有已配置好的
PDO或MySQLi实例,且该实例已禁用模拟预处理:PDO::ATTR_EMULATE_PREPARES => false - 所有接受用户输入的参数(如
where条件、limit值、order字段)必须通过占位符传入,不能在 SQL 字符串里插值 - 如果类提供
raw()、expr()、setSql()这类方法,必须默认禁用,或仅限白名单内固定语句(如"NOW()")
动态表名/字段名必须白名单硬校验
预处理占位符 ? 和 :name 只能用于数据值,不能用于标识符(表名、列名、ORDER BY、GROUP BY)。自定义类若支持动态字段,就得提前约定允许范围,运行时只做匹配,不作任何转义。
- 例如排序字段:先定义
$allowedSortFields = ['id', 'created_at', 'status'],再用in_array($_GET['sort'], $allowedSortFields) ? $_GET['sort'] : 'id' - 表名映射更稳妥:
$tableMap = ['user' => 'users', 'order' => 'orders']; $realTable = $tableMap[$_GET['type']] ?? 'users'; - 绝对不要用
filter_var($input, FILTER_SANITIZE_STRING)处理字段名——它删 HTML 标签,不防 SQL 注入
IN 语句和批量参数要手动展开占位符
预处理不支持数组直接绑定到 IN (?),自定义类若封装了 whereIn(),必须动态生成对应数量的 ?,再把数组值平铺进参数列表。
立即学习“PHP免费学习笔记(深入)”;
- 错误写法:
"WHERE id IN (?)", [$ids]—— 这只会把整个数组转成字符串,变成IN ('Array') - 正确做法:先用
str_repeat('?,', count($ids) - 1) . '?'构造占位符串,再用array_values($ids)提取纯数值参数 - 注意类型一致性:整数数组就用
bind_param('i', ...),字符串数组用's',混合类型需拆开处理
别信“输入验证能替代预处理”
有人觉得“我用了 filter_var($id, FILTER_VALIDATE_INT),拼接就安全了”,这是错觉。整数校验防不了逻辑绕过(比如传 -1 OR 1=1),也防不了字符集攻击(如宽字节截断),更防不了业务层误用(比如把校验过的 ID 当用户名拼进另一个查询)。
- 输入验证是必要补充,不是替代方案:数字转
(int)、邮箱用FILTER_VALIDATE_EMAIL、长度超限直接return false - 但只要代码里还存在
"SELECT * FROM {$table} WHERE id = " . $id这种模式,验证就形同虚设 - 最危险的是“半预处理”:部分参数绑定,部分拼接——攻击者会专攻未绑定的那部分
真正难的不是写对一个 prepare(),而是让整个查询类的所有分支路径都走同一套绑定机制,且不允许任何例外。一旦放开一个口子(比如为“兼容旧逻辑”加个 unsafeRawQuery()),整套防护就归零。
相关文章
- hbase 可视化的成本究竟多高 07-29
- hbase 可视化存在哪些难点 07-29
- hbase 可视化的安全性怎样保障 07-29
- hbase 可视化的更新速度有多快 07-29
- hbase zookeeper 怎样处理节点加入 07-29
- hbase 数据抽取的效率如何提升 07-29