PHP自定义查询类防SQL注入的实用方法
直接通过字符串拼接构建 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() 方法,就必须动态生成对应数量的 ?,并将数组值平铺到参数列表中。
- 错误写法:
"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() 方法——那整套防护体系就会瞬间归零。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
如何配置Oracle可恢复空间分配以防止任务中断
启用可恢复空间分配需将RESUMABLE_TIMEOUT设为非零值(如3600秒),RAC环境需逐节点单独设置。该机制仅对ORA-01536等空间类错误生效,挂起期间事务锁定状态不变,超时自动中止。会话级启用需显式指定timeout和name,否则可能无效。
Redis集群升级配置文件不兼容 对照新旧参数手册转换
升级至Redis7 0配置不兼容须知:主从复制命令由slaveof改为replicaof否则报错;集群全量覆盖参数默认开启需改为关闭;TCP连接积压参数需与系统内核一致;访问控制列表默认用户无管理权限需授权;节点配置文件禁止手动编辑,应通过命令管理。
Oracle 19c补丁冲突问题修复方法详细步骤使用opatch apply命令
Oracle19c补丁冲突因新旧补丁修复重叠或文件冲突所致。需先确认OPatch版本、inventory一致性及执行用户正确性,再通过opatchprereq定位具体冲突。真实冲突可回退旧补丁或改用完整RU流程,RAC环境需逐节点检查inventory。
MySQL修改权限后为何必须执行FLUSH PRIVILEGES?
MySQL修改权限后是否执行FLUSHPRIVILEGES取决于修改方式。通过GRANT或ALTERUSER标准命令自动同步,无需手动刷新;直接UPDATEmysql user表则必须执行以刷新内存缓存。已存在连接不重载,需注意host匹配、认证插件兼容性及RELOAD权限。
SQL嵌套查询在电商订单报表中的应用实践
SQL嵌套查询在电商订单报表中适用于条件筛选,如快速圈定用户范围,但不适合替代关联分析。使用时需注意子查询空值导致IN失效、必须返回单列、MySQL5 7不支持LATERAL及CTE。聚合分析应依赖聚合加过滤,深层嵌套可用派生表或CTE分步处理。
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-08 07:04
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:02
2026-07-08 07:02
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

