问题:
我想知道下面的存储过程是否可以安全地避免 SQL 注入,并且我知道一般准则是使用参数化查询。但是,我不确定如何将参数化查询放入存储过程中。
上下文:
我正在使用flask/python 根据参数获取数据。数据是从存储过程中检索的,对于数据库连接,代码使用 pymysql libray。
param1 = request.get('param1')
param2 = request.get('param2')
param3 = request.get('param3')
pymysql.callproc('EXEC STORED_PROCEDURE_NAME', (param1, param2, param3))
在存储过程定义中,定义参数并编写选择查询。基于其他参数,将在选择查询中添加其他参数。
CREATE PROCEDURE `PROCEDURE_NAME`(PARAM1 VARCHAR(500),PARAM2 VARCHAR(500),PARAM3 VARCHAR(500))
BEGIN
set @query=concat("select * from TABLE1 WHERE column1 = SOME_VALUE");
IF param1 is not null THEN
set @query=concat(@query," AND COLUMN2 like '%"PARAM1"%'");
END iF;
IF param2 is not null THEN
set @query=concat(@query," AND COLUMN3 like '%"PARAM2"%'");
END iF;
IF param3 is not null THEN
set @query=concat(@query," AND COLUMN4 like '%"PARAM3"%'");
END iF;
SELECT @query1;
prepare st from @query1;
execute st;
END
这当然不是注射安全的:
虽然准备好的语句不支持执行多个语句,但您可以通过注入来获取其他数据
UNION
:
call procedure_name("%' UNION SELECT user, bank_account from bankaccounts WHERE '1' != '", NULL, NULL);
另外,不要忘记用
DEALLOCATE PREPARE
结束您的陈述。
这将是注入安全的(假设 TABLE1 中的列定义为 NOT NULL):
CREATE PROCEDURE `PROCEDURE_NAME`(PARAM1 VARCHAR(500),PARAM2 VARCHAR(500),PARAM3 VARCHAR(500))
BEGIN
SET @p1:=@p2:=@p3:= '%';
PREPARE stmt FROM "SELECT * FROM TABLE1 WHERE column1 = 'SOME_VALUE' AND
COLUMN2 LIKE ? AND COLUMN3 LIKE ? AND COLUMN4 LIKE ?";
IF param1 is not null THEN
SET @p1:= param1;
END iF;
IF param2 is not null THEN
SET @p2:= param2;
END iF;
IF param3 is not null THEN
SET @p3:= param3;
END iF;
EXECUTE stmt USING @p1,@p2,@p3;
DEALLOCATE PREPARE stmt;
END