Есть ли что-нибудь, что может быть помещено после предложения "ORDER BY", что может представлять угрозу безопасности? - PullRequest
24 голосов
/ 11 июля 2011

По сути, я хочу сделать следующее:

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.

Ответы [ 5 ]

30 голосов
/ 11 июля 2011

Да, для атак с использованием 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;
}

Даже если предложение ORDER BY является сложным, оно все равно состоит только из значений, которые вы предоставляете (при условии, что вы не позволяете пользователям редактировать его вручную). Вы все еще можете проверить, используя белый список.

Я должен также добавить, что я обычно не люблю показывать структуру своей базы данных в URL-адресах или других местах пользовательского интерфейса, и часто буду использовать псевдоним в параметрах в URL-адресах и сопоставлять ее с реальными значениями, используя хэш.

17 голосов
/ 11 июля 2011

Не рассчитывайте на то, что инъекция SQL в этот момент не вызовет проблемы;не разрешать ЛЮБОЕ SQL-инъекцию.В противном случае злоумышленник может определить очень сложный порядок, который может привести к серьезному замедлению работы вашей БД.

6 голосов
/ 11 июля 2011

Я предпочитаю делать белый список и обрабатывать строку параметра http отдельно от строки, которая интерполируется в SQL-запрос.

В следующем примере PHP ключами массива будут значения, передаваемые в качестве параметров http, своего рода символьная метка для различных схем упорядочения в соответствии с вашим веб-интерфейсом. Значения массива - это то, что мы хотим интерполировать в 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, даже если вы не можете использовать параметры запроса. Если клиент передает нераспознанное значение, ваш код игнорирует его и использует порядок по умолчанию.

  • Вам не нужно ничего дезинфицировать, поскольку ключи и значения в массиве написаны вами, программистом. Клиентский ввод может выбрать только один из возможных вариантов.

  • Ваш веб-интерфейс не раскрывает структуру вашей базы данных.

  • Вы можете делать заказы, которые соответствуют выражениям SQL или альтернативным ASC / DESC, как я показал выше.

  • Вы можете изменить структуру базы данных без изменения веб-интерфейса или наоборот.

Я рассматриваю это решение в своей презентации, Мифы и ошибки SQL-инъекций , а также в своей книге Антипаттерны SQL: предотвращение ловушек при программировании баз данных .

2 голосов
/ 11 июля 2011

Логика, построенная вокруг переменной $_GET['order'], должна быть такой же действительной при использовании с переменной $order_sanitized.Почему бы не очистить входные данные в первую очередь, а затем выполнить свою логику, чтобы она вписалась в оператор SELECT?

0 голосов
/ 11 июля 2011

Это все еще точка потенциального внедрения SQL. Вы зависите от внутренней реализации mysql_query. Что если в более поздней версии они изменят его на использование нескольких запросов?

Вы можете использовать mysql_real_escape_string.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...