在“ORDER BY”子句之后是否有可能构成安全风险的内容?

lrpiutwd  于 2022-10-22  发布在  PHP
关注(0)|答案(5)|浏览(158)

基本上,我想做的是:

mysql_query("SELECT ... FROM ... ORDER BY $_GET[order]")

很明显,他们可以通过在其中放置无意义的语句来轻松地创建SQL错误,但mysql_query只允许您执行1个查询,因此他们不能放置类似1; DROP TABLE ...的语句。
除了产生语法错误之外,恶意用户还会造成什么损害吗?
如果是,我该如何清理查询?
$_GET['order']变量有很多类似SQL的语法,所以我真的不想更改格式。
为了澄清,$_GET['order']不仅仅是一个字段/列。它可能类似于last_name DESC, first_name ASC

rqcrx0a6

rqcrx0a61#

是的,SQL注入攻击可以使用未转义的ORDER BY子句作为向量。这里有一个关于如何利用这一点以及如何避免这一问题的解释:
http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/
该博客文章建议使用白名单来验证ORDERBY参数,这几乎可以肯定是最安全的方法。
为了响应更新,即使子句很复杂,您仍然可以编写一个例程,根据白名单验证它,例如:

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;
}

即使ORDERBY子句很复杂,它仍然只由您提供的值组成(假设您不允许用户手动编辑它)。您仍然可以使用白名单进行验证。
我还应该补充一点,我通常不喜欢在URL或UI中的其他位置公开我的数据库结构,我经常会在URL中的参数中使用别名,并使用哈希将其Map到实际值。

8dtrkrch

8dtrkrch2#

不要指望此时的SQL注入目前不会导致问题;不允许任何SQL注入。如果没有别的,恶意攻击者可能会定义一个非常复杂的顺序,这可能会导致数据库严重减速。

e3bfsja2

e3bfsja23#

我更喜欢做白名单,并将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")

这具有以下优点:

  • 即使在不能使用查询参数的情况下,也可以防止SQL注入。如果客户端传递了一个无法识别的值,代码将忽略它并使用默认顺序。
  • 您不必对任何东西进行清理,因为数组中的键和值都是由程序员编写的。客户端输入只能选择您允许的选项之一。
  • 您的web界面不会显示您的数据库结构。
  • 您可以定制与SQL表达式或可选ASC/DESC对应的订单,如上所示。
  • 您可以在不更改web界面的情况下更改数据库结构,反之亦然。

我在我的演示文稿SQL Injection Myths & Fallacies和我的书SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming中介绍了这个解决方案。

u1ehiz5o

u1ehiz5o4#

围绕变量$_GET['order']构建的逻辑在用于变量m1on1o1p时应该同样有效。为什么不首先清理输入,然后执行逻辑,使其适合SELECT语句?

xpcnnkqh

xpcnnkqh5#

它仍然是潜在的SQL注入点。您依赖于mysql_query的内部实现。如果在更高版本中,他们将其更改为使用多个查询,该怎么办?
您可以使用mysql_real_escape_string

相关问题