在SQL注入中,存储过程中的预准备语句是否安全?

时间:2011-08-28 10:26:27

标签: php mysql stored-procedures sql-injection

在MySQL中,是一个在SQL注入中保存的存储过程中的预准备语句吗?见下面的例子。 get_info存储过程传递一个表名(pTbl)和where子句(pWhere)。 p可以有多个AND(例如fld1 =“a”AND fld2 =“b”AND ...)。这可能不是最好的方法,但我需要动态的SQL。

CREATE PROCEDURE get_info(pTbl VARCHAR(10), pWhere TEXT)
BEGIN
    SET @uSQL = CONCAT('SELECT info FROM ',pTbl,' WHERE ',pWhere);
    PREPARE ps FROM @uSQL;
    EXECUTE ps;
END$$

我尝试使用MySQL查询浏览器调用下面的存储过程,但只是在我的SQL中出现语法错误时才收到错误。

CALL get_info('tbl','1=1;SELECT * FROM information_schema.TABLES;');

如果它有助于使用PDO从PHP调用任何存储过程,如下所示。 $ tbl是$ _SESSION变量,$ whr是$ _GET变量。

$s=$c->prepare("CALL get_info(?,?)");
$s->execute(array($tbl,$whr));

此存储过程是否安全?如果没有,我将如何注射它?如果我从MySQL查询浏览器注入到网页,它会有所作为吗?感谢...

3 个答案:

答案 0 :(得分:2)

是的,这是安全的。 (编辑:不,不是)

关键是要知道SQL文本何时被分析并转换为语义树。准备好的语句就是:准备好的语句,只是等待参数。它们存储在完全编译到内部执行计划的服务器中,缺少参数的“漏洞”。

这就是为什么你得到语法错误,你试图将整个WHERE部分设置为参数;但它是一个完整的表达树。准备好的语句只能有数据元素的“漏洞”,而不能用于语法文本。

传递参数的协议是完全二进制安全的,无论你在参数变量中有什么,它们都将作为二进制数据发送并仅用作数据,而不是作为SQL命令的一部分。

修改 哎呀!我刚刚注意到你正在进行文本插值,不是在PHP中而是在SQL中。这意味着您将在以后使用外部数据构建S​​QL命令。

绝对不安全。

答案 1 :(得分:1)

由于其中一个值来自用户,因此可以使用某些形式的SQL注入;虽然只能运行SELECT查询,但仍可以通过将1=1传递给页面来显示信息。以这种方式显示的信息的实际有用性可能很低,但仍然可能发生。

答案 2 :(得分:1)

任何时候将值插入到语句中都有注入的可能性。该程序很脆弱。 SQL过程和函数中注入的唯一一般限制是PREPARE适用于单个语句。在这种特定情况下,注入的文本在WHERE中的SELECT子句之后基本上限制了对子选择的攻击,UNION,调用过程和函数(棘手但可能非常危险) ,并转储到文件(如果get_info的定义者具有FILE权限)。

举个例子,试试:

CALL get_info('tbl','1=0 UNION SELECT CONCAT(user, "@", host, " ", password) FROM mysql.user;');