在"ORDER BY"条款之后可以提出任何可能造成安全风险的事情吗?

mpe*_*pen 24 php mysql database sql-injection

基本上,我想要做的是:

mysql_query("SELECT ... FROM ... ORDER BY $_GET[order]")
Run Code Online (Sandbox Code Playgroud)

他们显然可以通过在其中放置无意义来轻松地创建SQL错误,但mysql_query只允许执行1个查询,因此他们不能放置类似的东西1; DROP TABLE ....

除了创建语法错误之外,恶意用户是否可以做任何损害?

如果是这样,我该如何清理查询?

$_GET['order']变量中有很多逻辑构建在类似SQL的语法中,所以我真的不想改变格式.


澄清$_GET['order']一下,不只是单个字段/列.它可能是这样的last_name DESC, first_name ASC.

Raf*_*afe 30

是的,SQL注入攻击可以使用未转义的ORDER BY子句作为向量.这里有一个解释如何利用它以及如何避免这个问题:

http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/

该博客文章建议使用白名单来验证ORDER BY参数,这几乎肯定是最安全的方法.


要响应更新,即使该子句很复杂,您仍然可以编写一个针对白名单验证它的例程,例如:

function validate_order_by($order_by_parameter) {
    $columns = array('first_name', 'last_name', 'zip', 'created_at');

    $parts = preg_split("/[\s,]+/", $order_by_parameter);

    foreach ($parts as $part) {
        $subparts = preg_split("/\s+/", $part);

        if (count($subparts) < 0 || count($subparts) > 2) {
           // Too many or too few parts.
           return false;
        }

        if (!in_array($subparts[0], $columns)) {
           // Column name is invalid.
           return false;
        }

        if (count($subparts) == 2 
            && !in_array(strtoupper($subparts[1]), array('ASC', 'DESC')) {
          // ASC or DESC is invalid
          return false;
        }
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

即使ORDER BY子句很复杂,它仍然仅使用您提供的值(假设您不允许用户手动编辑它).您仍然可以使用白名单进行验证.

我还应该补充一点,我通常不喜欢在URL或UI中的其他位置公开我的数据库结构,并且通常会在URL中的参数中对这些内容进行别名,并使用哈希将其映射到实际值.


Pau*_*ier 17

不要指望当时的SQL注入不会导致问题; 不允许任何SQL注入.如果不出意外,恶意攻击者可以定义一个非常复杂的订单,这可能会导致数据库严重减速.


Bil*_*win 6

我更喜欢进行白名单,并将http参数字符串视为与插入到SQL查询中的字符串分开.

在下面的PHP示例中,数组键将是作为http参数传递的值,根据您的Web界面,用于不同排序方案的某种符号标签.数组值将是我们想要为这些相应的排序方案插入SQL的内容,例如列名或表达式.

<?php

$orderby_whitelist = array(
  "name"    => "last_name, first_name",
  "date"    => "date_created",
  "daterev" => "date_created DESC",
  "DEFAULT" => "id"
);

$order = isset($_GET["order"]) 
  ? $_GET["order"] 
  : "DEFAULT";
$order_expr = array_key_exists($order, $orderby_whitelist) 
  ? $orderby_whitelist[$order] 
  : $orderby_whitelist["DEFAULT"];

mysql_query("SELECT ... FROM ... ORDER BY $order_expr")
Run Code Online (Sandbox Code Playgroud)

这有以下优点:

  • 即使在不能使用查询参数的情况下,也可以防御SQL注入.如果客户端传递了无法识别的值,则代码会忽略它并使用默认顺序.

  • 您不必清理任何内容,因为数组中的键和值都是由程序员编写的.客户输入只能选择您允许的其中一个选项.

  • 您的Web界面不会显示您的数据库结构.

  • 您可以制作与SQL表达式或替代ASC/DESC相对应的自定义订单,如上所示.

  • 您可以在不更改Web界面的情况下更改数据库结构,反之亦然.

我在演示文稿,SQL注入神话和谬误,以及我的书" SQL反模式:避免数据库编程的陷阱"中介绍了这个解决方案.