2

我注意到很多人都说可以创建注入攻击,但我的理解是,如果有人从字符串而不是参数创建查询。为了测试存储过程不能保护您免受注入攻击的说法,我提出这个例子是希望有人可以向我展示一个漏洞(如果有的话)。

请注意,我以这种方式构建了代码,以便轻松插入调用过程的函数并将其嵌入到 SELECT 查询中。这意味着我无法创建准备好的语句。理想情况下,我希望以这种方式保持我的设置,因为它是动态且快速的,但如果有人可以创建有效的注入攻击,显然这不会发生。

DELIMITER $$

#This procedure searches for an object by a unique name in the table.
#If it is not found, it inserts. Either way, the ID of the object
#is returned.

CREATE PROCEDURE `id_insert_or_find` (in _value char(200), out _id bigint(20))
BEGIN
    SET @_value = _value;
    SET @id = NULL;
    SELECT id INTO _id FROM `table` WHERE name=_value;

    IF _id IS NULL THEN
        BEGIN
            INSERT INTO `table` (`name`) VALUE (_value);
            SELECT LAST_INSERT_ID() INTO _id;
        END;
    END IF;
END$$

CREATE FUNCTION `get_id` (_object_name char(200)) RETURNS INT DETERMINISTIC
BEGIN
    SET @id = NULL;
    call `id_insert_or_find`(_object_name,@id);

    return @id;
END$$

PHP 代码

我在这里使用的 PHP 代码是:

注意,Boann 在下面指出了这段代码的愚蠢之处。我不是为了尊重答案而对其进行编辑,但它肯定不会是代码中的直接查询。它将使用 ->prepare 进行更新,等等。如果发现新的漏洞,我仍然欢迎任何额外的评论。

function add_relationship($table_name,$table_name_child) {
    #This table updates a separate table which has 
    #parent/child relationships listed.
    $db->query("INSERT INTO table_relationships (`table_id`,`tableChild_id`) VALUES (get_id('{$table_name}'),get_id('{$table_name_child}')");
}

最终结果是

table `table`
id      name
1       oak
2       mahogany

现在,如果我想让橡木成为桃花心木的孩子,我可以使用

add_relationship("mahogany","oak");

如果我想让塑料成为橡木的孩子,我可以使用

add_relationship("oak","plastic");

希望这有助于提供一些框架和背景。

4

2 回答 2

4

不安全的不一定是存储过程,而是您调用它的方式。

例如,如果您执行以下操作:

mysqli_multi_query("CALL id_insert_or_find(" + $value + ", " + $id + ")");

那么攻击者将设置$value="'attack'" and id="1); DROP SCHEMA YOUR_DB; --"

那么结果将是

mysqli_multi_query("CALL id_insert_or_find('attack', 1); DROP SCHEMA YOUR_DB; --)");

轰炸机

于 2013-07-31T03:39:05.780 回答
3

严格来说,应该编写该查询以转义表名:

$db->query("INSERT INTO table_relationships (`table_id`,`tableChild_id`) " .
    "VALUES (get_id(" . $db->quote($table_name) + ")," .
    "get_id(" . $db->quote($table_name_child) . "))");

否则,如果其中一个参数包含单引号,它将脱离引号。如果您只在代码中使用文字字符串(例如,add_relationship("mahogany", "oak");)调用该函数,那么不转义它是安全的。如果您可能曾经add_relationship使用来自 $_GET/$_POST/$_COOKIE 或其他数据库字段或文件等的数据进行调用,那么它就是在自找麻烦。我当然不会让它通过代码审查。

如果用户可以控制提供给该函数的表名,那么他们可以这样做,例如:

add_relationship("oak", "'+(SELECT CONCAT_WS(',', password_hash, password_salt) FROM users WHERE username='admin')+'");

现在您可能会说,如果结果表名不存在,则没有实用的方法来提取该信息,但即便如此,您仍然可以使用二进制搜索和单独的查询一次提取一个二进制位信息,只需打破询问。像这样的东西(未测试确切的语法):

add_relationship("oak", "plastic'+(IF(ORD(SUBSTR(SELECT password_hash FROM users WHERE username='admin'),1,1)>=128, 'foo', ''))+'");

真的,只是转义参数更容易,然后你就不用担心了。

于 2013-07-31T04:52:17.757 回答