让我们说我想编写一个过程,使我可以在某些列上调用某些函数,例如:
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服务器版本的正确语法, 在第一行的'(?)from table'附近使用
答案 0 :(得分:1)
您无法对列/表/函数名称/别名进行参数设置。同样,PREPARE
语句仅允许将SQL查询的“值”部分用作参数。函数/表/列名/别名用于确定SQL语句的有效性;因此无法在运行时执行期间更改。在执行时更改它可能会更改SQL语句是否有效。
您可以将其视为编译代码。因此,编译器必须知道用于创建有效可执行文件的所有函数/类名称等(是的,我们可以执行动态类,但这是 rare )。另一方面,我们可以更改程序的输入“值”,但是通常不能更改要对输入数据执行的操作。
此外,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 ;
答案 1 :(得分:0)
可以在关键字中参数化SQL关键字的唯一方法是使用动态查询。需要注意的是,动态查询往往比静态查询要慢,主要是因为它们不容易被缓存。
在没有警告的情况下,应该可以执行以下操作:
const fs = require("fs");
const Discord = require("discord.js");
module.exports.run = async(bot, message, args, con) => {
fs.readdir("./commands/", (err, files) => {
if(err) console.error(err);
let jsfiles = files.filter(f => f.split(".").pop() === "js");
if(jsfiles.length <= 0) {
console.log("No commands to load!");
return;
}
var namelist = "";
var desclist = "";
var usage = "";
let result = jsfiles((f, i) => {
let props = require(`./${f}`);
namelist = props.help.name;
desclist = props.help.description;
usage = props.help.usage;
// send help text
let helpembed = new Discord.RichEmbed()
.setTitle("Commands")
.setFooter("Please report any bugs to Vati#1662")
.setColor("RANDOM")
.addField(`**${namelist}** \n${desclist} \n${usage}`)
message.author.sendEmbed(helpembed);
});
})
}
module.exports.help = {
name: "help",
description: "shows all commands",
usage: "help"
}