2

我使用的一些存储过程需要根据是否提供了过程输入参数来插入 WHERE 标准。为了避免潜在的注入点,我想对将成为插值标准一部分的值使用参数绑定。

由于添加到准备好的语句的标准以及要绑定的参数数量可能会因用户输入而异,因此我设计了以下方法来确定哪些变量将传递给 EXECUTE 语句。这行得通,但似乎不优雅。

CREATE PROCEDURE foo (IN mandatory INT, IN optional INT, IN optional2 VARCHAR(20))
  BEGIN

    SELECT
      0, '', '', mandatory, optional, optional2
    INTO 
      @params, @sql, @where, @m, @o1, @o2;

    IF (@o1 > '' AND @o1 IS NOT NULL) THEN
      SET @where = CONCAT(@where, ' AND field = ?');
      SET @params = @params + 1;
    END IF;
    IF (@o2 > '' AND @o2 IS NOT NULL) THEN
      SET @where = CONCAT(@where, ' AND field2 = ?');
      SET @params = @params + 3;
    END IF;

    SET @sql = CONCAT('
      SELECT id, bar FROM table
      WHERE
        baz = ?
        ', @where
    );
    PREPARE STMT FROM @sql;
    CASE @params
      WHEN 0 THEN EXECUTE STMT USING @m;
      WHEN 1 THEN EXECUTE STMT USING @m, @o1;
      WHEN 3 THEN EXECUTE STMT USING @m, @o2;
      WHEN 4 THEN EXECUTE STMT USING @m, @o1, @o2;
    END CASE;
    DEALLOCATE PREPARE STMT;

  END$$

我知道替代方案:

  • 调用这些存储过程的二进制文件有一个函数,该函数通过正则表达式传递用户提供的字符串来尝试识别潜在的 SQL 注入。
  • 给定动态数量的输入,用户定义的函数可用于动态构造 EXECUTE 语句。

但是,我想知道是否有其他人遇到过这种纯粹使用 SQL 来处理 EXECUTE 语句的动态构造的愿望。

4

2 回答 2

1
However, I was wondering if anyone else has ran into this desire to 
handle dynamic construction of an EXECUTE statement purely with SQL.

我也是。

这是一个 PHP 解决方案,用于根据未知长度的数组为准备好的语句生成问号列表:

/* My target query is this:
   SELECT fun FROM fun_stuff WHERE fun_key IN ( ...unknown number of values... )
*/

/* For this example let's set our array to this: */
$val_arr = array(1,2,3,4,5,6,7,8,9);
$val_arr_cnt = count($val_arr); /* and count it */

/* Now make prepared statement q-mark string from values array */
$sql_prep = str_pad('?', ($val_arr_cnt * 2) - 1, ',?', STR_PAD_RIGHT);

/* add it to query */
$sql = "SELECT fun FROM fun_stuff WHERE fun_key IN ($sql_prep)";

/* And the result:
   SELECT fun FROM fun_stuff WHERE fun_key IN (?,?,?,?,?,?,?,?,?)
 */

我不知道这有多有效。但是我也时不时想要实现 MySQL 准备语句的安全性和效率但有可变长度输入数组

于 2014-08-29T00:15:25.850 回答
0

不确定是否可以动态构建参数列表(动态更改参数数量等)。但是由于您可以动态构建 where 子句,因此一个非常简单的解决方法是执行类似的操作。假设您的验证允许它,else 子句基本上与忽略您可能会或可能不会过滤的参数具有相同的效果。

if p_cust_id is not null && p_cust_id > 0 then
    set v_where_clause = concat(v_where_clause, ' c.cust_id = ? ');
    set @v_cust_id := p_cust_id;
else
    set v_where_clause = concat(v_where_clause, ' c.cust_id > ? ');
    set @v_cust_id := 0;
end if;

然后将上面的所有用户变量插入到您的执行语句中

execute str1 using @v_cust_id, @v_etc....;*
于 2015-12-03T05:26:52.180 回答