PHP使用JSON_ARRAY更新MySQL JSON字段异常及安全性问题咨询
正确更新JSON字段的方案
格式错误原因:
implode('","', $p_cat)得到的是字符串1","5,绑定到SQL后,PDO会将整个字符串作为单个参数传入JSON_ARRAY(),同时自动转义字符串中的双引号,最终JSON_ARRAY("1\",\"5")的执行结果就是单个元素的数组["1\",\"5"],和预期不符。另外调用代码中的foreach逻辑完全无效,循环绑定同一个:value参数只会保留最后一次绑定的值。
方案1:修改jsonArray方法适配多值绑定
调整jsonArray方法,自动为数组每个元素生成独立占位符,避免字符串拼接转义问题:
public function jsonArray($table, $item, $valueArr, $where = null) { // 为数组每个元素生成独立占位符 $placeholders = []; $bindParams = []; foreach($valueArr as $k => $v) { $placeholder = 'json_val_'.$k; $placeholders[] = ':'.$placeholder; $bindParams[$placeholder] = $v; } $sql = 'UPDATE '.$table.' SET '.$item.' = JSON_ARRAY('.implode(',', $placeholders).')'; if ($where != null) { $sql .= ' WHERE ' . $where; } $this->sql = $sql; // 暂存待绑定的JSON参数 $this->jsonBindParams = $bindParams; return $this->sql; }
调用代码调整为:
require_once 'crud.php'; $dbh = new Database(); $p_cat = [1,5]; // 直接传入数组生成SQL $upOn = $dbh->jsonArray('restaurant_list', 'restaurant_order', $p_cat, 'id = :id'); $dbh->prepare($upOn); // 批量绑定JSON数组元素 foreach($dbh->jsonBindParams as $k => $v) { $dbh->bind($k, $v); } // 绑定查询条件 $dbh->bind('id', 1); $dbh->execute();
方案2:直接存入JSON序列化字符串(更简便)
MySQL的JSON字段原生支持合法JSON字符串直接写入,无需调用JSON_ARRAY函数,不需要修改原有类,直接调整调用代码即可:
require_once 'crud.php'; $dbh = new Database(); $p_cat = [1,5]; // 直接写更新SQL $dbh->sql = "UPDATE restaurant_list SET restaurant_order = :json_val WHERE id = :id"; $dbh->prepare(); // 把数组转成JSON字符串直接绑定 $dbh->bind('json_val', json_encode($p_cat)); $dbh->bind('id', 1); $dbh->execute();
安全漏洞说明
现有代码存在2个高危安全问题,无法完全抵御攻击:
- SQL注入风险:
jsonArray方法中的$table、$item、$where三个参数直接拼接进SQL语句,没有做任何白名单校验。预处理机制仅对绑定的参数生效,直接拼接的SQL部分不受保护,只要这三个参数有用户可控的场景,就会存在SQL注入漏洞。 - 错误过滤破坏数据:
strSafe方法中的strip_tags、移除多余空格逻辑会破坏合法JSON格式,如果JSON数据中包含正常的HTML标签、连续空格,会被过滤导致JSON解析失败,且该过滤逻辑对SQL注入没有任何防御作用,属于多余的错误逻辑。
仅当$table、$item、$where三个参数完全是开发者写死的固定值时,现有代码才能避免SQL注入风险。
内容的提问来源于stack exchange,提问作者Abu Rayane
相关产品推荐
相关产品推荐

