Веб-приложение может формировать SQL-запросы, опираясь на данные, получаемые от пользователя. Из-за недостаточной обработки данных, злоумышленник может внедрить операторы SQL, тем самым изменить логику запроса, обрабатываемого базой данных. В ряде случаев злоумышленник не ограничен одним лишь чтением информации из базы данных. Также существует возможность читать произвольные файлы, создавать новые, проводить атаки, направленные на отказ в обслуживании. Развивая атаку, можно завладеть исходными кодами веб-приложения, загрузить и впоследствии выполнить вредоносный код.

Пример уязвимого сценария:

if (isset($_GET['id'])) {
    try {
        $dbh = new PDO('mysql:dbname=test;host=127.0.0.1', 'root', 'pass');
    } catch (PDOException $e) {
        echo "Connection failed\n";
        exit;
    }
    $stm = $dbh->query("SELECT * FROM users WHERE id=" . $_GET['id']);
    $user = $stm->fetch();
    echo "User name: " . $user['name'] . "\n";
}

Злоумышленник может получить произвольные данные, например версию базы данных, передав в параметре id следующую строку: 0+union+select+1,version().

Рисунок 1. Пример атаки «Внедрение SQL-кода»

Рекомендации

Для защиты от атак «Внедрение операторов SQL», рекомендуется приводить значение переменной к целочисленному типу.

if (isset($_GET['id'])) {
    try {
        $dbh = new PDO('mysql:dbname=test;host=127.0.0.1', 'root', 'pass');
    } catch (PDOException $e) {
        echo "Connection failed\n";
        exit;
    }
    $stm = $dbh->query("SELECT * FROM users WHERE id=" . (int)$_GET['id']);
    $user = $stm->fetch();
    echo "User name: " . $user['name'] . "\n";
}

Хорошим решением будет использование в коде приложения параметризированных SQL-запросов вместо простой конкатенации переменных с шаблоном запроса.

if (isset($_GET['id'])) {
    try {
        $dbh = new PDO('mysql:dbname=test;host=127.0.0.1', 'root', 'pass');
    } catch (PDOException $e) {
        echo "Connection failed\n";
        exit;
    }
    $stm = $dbh->prepare("SELECT name FROM users WHERE id=?");
    $stm->execute(array($_GET['id']));
    $user = $stm->fetch(PDO::FETCH_ASSOC);
    echo "User name: " . $user['name'] . "\n";
}

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

Ссылки