假设我想编写一个程序,允许我在某些列上调用某些函数,例如:
call foo('min','age') -> SELECT min(age) FROM table;
我希望我的程序免受 sql 注入的影响,因此,我愿意使用准备好的语句并对输入进行参数化
SET @var = "SELECT ?(?) FROM table;"
PREPARE x FROM @var;
EXECUTE x USING a, b;
其中 a 和 b 分别是输入参数、函数和列。
但是,这似乎是不可能的 - 每当我想执行此语句时,InnoDB 都会不断抛出错误。
是否可以通过这种方式解决这个问题,或者我需要诉诸白名单?
编辑:完整代码:
create procedure test(in func varchar(20), in col varchar(20))
begin
set @f = func;
set @c = col;
set @sql = "select ?(?) from table;";
prepare x from @sql;
execute x using @f, @c;
end;
调用:
call test('min','age');
完整错误:
[42000][1064] 你的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在第 1 行的“(?) from table”附近使用的正确语法
您不能参数化列/表/函数名称/别名。因为,PREPARE
语句只允许将 SQL 查询的“值”部分用作参数。函数/表/列名/别名用于判断SQL语句的有效性;因此不能在运行时执行期间更改。在执行时更改它可能会改变 SQL 语句是否有效。
您可以将其视为编译代码;因此编译器必须知道所有函数/类名等以创建有效的可执行文件(是的,我们可以做动态类,但这种情况很少见)。另一方面,我们可以改变程序的输入“值”,但一般不能改变对输入数据进行的操作。
此外,MySQL 服务器会将参数视为文字,并在它们周围应用引号,然后在查询执行中使用它们。
现在,在您的情况下,您仍然可以使用函数名称作为存储过程的参数,并使用它生成查询字符串。但是您不能将其用作查询本身的参数。
delimiter $$
create procedure test(in func varchar(20), in col varchar(20))
begin
set @c = col;
-- use concat function to generate the query string using func parameter
set @sql = concat('select ', func, '(?) from table');
-- prepare the statement
prepare stmt from @sql;
-- execute
execute x using @c;
-- don't forget to deallocate the prepared statement
deallocate prepare stmt;
end$$
delimiter ;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句