为什么MySQL允许SELECT查询中的非完全匹配?

时间:2015-05-05 20:23:58

标签: mysql sql database security

这是故事。我正在测试使用MySQL数据库作为数据主存储运行的Laravel(PHP框架)应用程序的一些安全测试(使用zaproxy)。

Zaproxy报告了一个可能的SQL注入,用于具有以下有效负载的POST请求URL:

id[]=3-2&enabled[]=on

基本上,这是一个AJAX请求来打开/关闭列表中的特定功能。 Zaproxy对请求进行模糊测试:id值为3-2时,应该有一个整数 - 要更新的项的id

问题是此请求正在运行。它应该失败,但代码实际上正在更新id = 3

的项目

我按照我应该的方式做事:使用Eloquent的Model::find($id)方法检索模型,从请求传递id值(经过一些调查后,被确定为字符串“3-2”)。 AFAIK,Eloquent库应该通过将ID值绑定到参数来执行查询。

我尝试使用Laravel的DB类执行查询,代码如下:

$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));

并得到id = 3的行。

然后我尝试对我的MySQL数据库执行以下查询:

SELECT * FROM table WHERE id='3-2';

检索id = 3所在的行。我也尝试了另一个值:“3abc”。看起来像以数字为前缀的任何值将检索一行。

最终,这似乎是MySQL的一个问题。就我而言,如果我要求id = '3-2'行并且没有具有该确切ID值的行,那么我希望它返回一组空的结果。

我有两个问题:

  1. 有没有办法改变这种行为?它似乎是在数据库服务器级别,所以数据库服务器配置中有什么东西可以防止这种情况发生吗?

  2. 这对我来说似乎是一个严重的安全问题。 Zaproxy能够注入一些任意值并对我的数据库进行更改。不可否认,对于我的应用程序来说,这是一个相当小的问题,并且(可能)唯一可行的值将是以数字为前缀的值,但仍然......

4 个答案:

答案 0 :(得分:1)

SELECT * FROM table WHERE id= ? AND ? REGEXP "^[0-9]$";

这比我在上面的评论中建议的要快。 编辑:啊,我看到你无法改变查询。然后确认,您必须清理代码中的输入。另一个 非常糟糕和肮脏的 选项,如果您处于奇怪的情况,您无法更改查询但可以更改数据库,则将id字段更改为[VAR] CHAR。

答案 1 :(得分:1)

我认为这是由于MySQL在与数字数据类型进行比较时自动将字符串转换为数字。

https://dev.mysql.com/doc/refman/5.1/en/type-conversion.html

  

的MySQL> SELECT 1> ' 6×&#39 ;;

     

- > 0

     

的MySQL> SELECT 7> ' 6×&#39 ;;

     

- > 1

     

的MySQL> SELECT 0> ' 5233&#39 ;;

     

- > 0

     

的MySQL> SELECT 0 =' x6';

     

- > 1

你真的只想在MySQL周围装甲,以防止这样的字符串被比较。也许切换到不同的SQL服务器。

答案 2 :(得分:1)

如果没有重写一堆代码,那么说实话,正确的答案就是

  

这是一个非问题

Zaproxy甚至声称它可能一个SQL注入攻击,这意味着它不知道!它从来没有说过"嗯,是的,我们通过将x-y-and-z传递给你的查询来删除表格"

// if this is legal and returns results
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));

// then why is it an issue for this
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));

// to be interpreted as
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));

您正在参数化您的查询,因此Zaproxy不在其中。

答案 3 :(得分:0)

这是我最后做的事情:

首先,我怀疑我的期望有点不合理。我期待如果我使用参数化查询,我不需要清理我的输入。事实显然并非如此。虽然参数化查询消除了一些最有害的SQL注入攻击,但此示例表明仍需要检查您的输入并确保您从用户那里获得正确的内容。

所以,说了......我决定写一些代码来更容易地检查ID值。我在我的应用程序中添加了以下特征:

trait IDValidationTrait
{
    /**
     * Check the ID value to see if it's valid
     *
     * This is an abstract function because it will be defined differently
     * for different models. Some models have IDs which are strings,
     * others have integer IDs
     */
    abstract public static function isValidID($id);

    /**
     * Check the ID value & fail (throw an exception) if it is not valid
     */
    public static function validIDOrFail($id)
    {
        ...
    }

    /**
     * Find a model only if the ID matches EXACTLY
     */
    public static function findExactID($id)
    {
        ...
    }

    /**
     * Find a model only if the ID matches EXACTLY or throw an exception 
     */
    public static function findExactIDOrFail($id)
    {
        ...
    }
}

因此,每当我通常在我的模型类上使用find()方法来检索模型时,我会使用findExactID()findExactIDOrFail(),这取决于我想如何处理错误。

感谢所有评论过的人 - 您帮助我集中思考并更好地了解发生了什么。