PHP实现Mysql动态查询时防范SQL注入的可靠方案咨询
动态查询场景下的SQL注入防护方案
动态拼接查询条件完全可以和预处理语句兼容,不用直接把用户输入拼进SQL字符串,核心思路是分开维护条件片段和待绑定的参数数组,具体改造方法如下:
改造步骤
- 初始化两个数组,一个存SQL条件片段,一个存要绑定的参数:
$conditions = []; $params = [];
- 逐个判断查询参数,拼接条件时用占位符
?代替用户输入,同时把用户输入存入参数数组:
// 处理sub_cat参数 if(isset($_GET['sub_cat']) && $_GET['sub_cat'] !== ''){ $conditions[] = 'ad_sub_cat = ?'; $params[] = $_GET['sub_cat']; } // 处理ad_brand模糊查询 if(isset($_GET['ad_brand']) && $_GET['ad_brand'] !== ''){ $conditions[] = '`ad_brand` LIKE ?'; // 模糊查询的百分号直接加在参数值上,不要拼进SQL $params[] = "%{$_GET['ad_brand']}%"; } // 处理最小价格,提前转数值更安全 if(isset($_GET['min_range']) && $_GET['min_range'] !== '' && is_numeric($_GET['min_range'])){ $conditions[] = 'ad_price >= ?'; $params[] = (float)$_GET['min_range']; } // 处理最大价格 if(isset($_GET['max_range']) && $_GET['max_range'] !== '' && is_numeric($_GET['max_range'])){ $conditions[] = 'ad_price <= ?'; $params[] = (float)$_GET['max_range']; } // 处理for_r_s参数,如果是枚举值可以加白名单校验 if(isset($_GET['for_r_s']) && $_GET['for_r_s'] !== ''){ // 示例:如果for_r_s只能是0或1,加白名单判断,更安全 if(in_array($_GET['for_r_s'], ['0','1'])){ $conditions[] = 'for_r_s = ?'; $params[] = $_GET['for_r_s']; } } // 拼接基础SQL $sql = "SELECT posts.ID, posts.ad_title, posts.ad_price, posts.ad_location, posts.ad_sub_cat FROM `posts`"; if(!empty($conditions)){ $sql .= ' WHERE ' . implode(' AND ', $conditions); }
- 用预处理执行查询,以PDO为例:
$pdo = new PDO('mysql:host=你的主机;dbname=你的库名;charset=utf8mb4', '用户名', '密码'); $stmt = $pdo->prepare($sql); $stmt->execute($params); // 读取结果 $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
如果用mysqli,逻辑完全一致,只是绑定参数的写法对应调整即可。
额外安全优化
- 数值类型的参数提前做类型转换或者格式校验,避免非法参数传入
- 枚举类的参数(比如分类、状态类字段)增加白名单校验,只有在允许范围内的参数才拼接对应条件
- 数据库账号配置最小权限,查询业务的账号不要给写、删表等多余权限,就算出问题也能降低损失
内容的提问来源于stack exchange,提问作者DB_cont
相关产品推荐
相关产品推荐

