💉 Что такое SQL-инъекция и как ее предотвратить в PHP-приложениях

Если вы уже знаете, что такое SQL-инъекция, смело переходите ко второй половине статьи.

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

Что такое SQL-инъекция?

Ключ к пониманию SQL-инъекций находится в его названии: SQL + Injection.

Слово «инъекция» здесь не имеет каких-либо медицинских коннотаций, а скорее является использованием глагола «внедрить».

Вместе эти два слова воплощают идею внедрения SQL в веб-приложение.

Ввод SQL в веб-приложение. , , ммм , , Разве это не то, что мы делаем в любом случае?

Да, но мы не хотим, чтобы злоумышленник управлял нашей базой данных.

Давайте разберемся с этим на примере.

Допустим, вы создаете типичный веб-сайт PHP для местного магазина электронной коммерции, поэтому вы решили добавить контактную форму, например:

<form action="record_message.php" method="POST">

  <label>Your name</label>

  <input type="text" name="name">



  <label>Your message</label>

  <textarea name="message" rows="5"></textarea>



  <input type="submit" value="Send">

</form>

И давайте предположим, что файл send_message.php хранит все в базе данных, чтобы владельцы магазина могли читать пользовательские сообщения.

Например такой код:

<?php



$name = $_POST['name'];

$message = $_POST['message'];



// check if this user already has a message

mysqli_query($conn, "SELECT * from messages where name = $name");



// Other code here

Итак, вы сначала пытаетесь увидеть, есть ли у этого пользователя непрочитанное сообщение. Запрос SELECT * from messages where name = $name, кажется достаточно простым, верно?

НЕПРАВИЛЬНО!

Теперь мы открыли двери для мгновенного уничтожения нашей базы данных.

Для этого злоумышленнику необходимо выполнить следующие условия:

  • Приложение работает на базе данных SQL (сегодня почти каждое приложение работает на SQL)
  • Текущее подключение к базе данных имеет разрешения «редактировать» и «удалять» в базе данных.
  • Названия важных таблиц можно угадать

Третий момент означает, что теперь, когда злоумышленник знает, что вы управляете магазином электронной коммерции, вы, скорее всего, сохраните данные заказа в таблице orders.

Вооружившись всем этим, все, что нужно сделать злоумышленнику, это указать имя:

Joe; truncate orders;

Давайте посмотрим, каким будет запрос, когда он будет выполнен скриптом PHP:

SELECT * FROM messages WHERE name = Joe; truncate orders;

Хорошо, в первой части запроса есть синтаксическая ошибка (без кавычек вокруг «Joe»), но точка с запятой вынуждает движок MySQL начать интерпретацию нового: truncate orders.

Просто так, одним махом, вся история заказов исчезла!

Теперь, когда вы знаете, как работает SQL-инъекция, пришло время посмотреть, как это остановить. Для успешного внедрения SQL необходимо выполнить два условия:

  1. Скрипт PHP должен иметь права на изменение / удаление базы данных. Я думаю, что это верно для всех приложений, и вы не сможете сделать ваши приложения доступными только для чтения. И подумайте, что, даже если мы удалим все привилегии на изменение, SQL-инъекция все еще может позволить кому-то запускать запросы SELECT и просматривать всю базу данных, включая конфиденциальные данные. Другими словами, снижение уровня доступа к базе данных не работает, ведь ваше приложение все равно нуждается в этом.
  2. Пользовательский ввод обрабатывается. Единственный способ внедрения SQL-кода – это когда вы принимаете данные от пользователей. Еще раз, не практично останавливать все входные данные для вашего приложения только потому, что вы беспокоитесь о внедрении SQL.

Предотвращение внедрения SQL инъекуции в PHP

Теперь, учитывая, что соединения с базой данных, запросы и пользовательские вводы являются частью жизни БД, то как мы можем предотвратить внедрение SQL?

К счастью, это довольно просто, и есть два способа сделать это:

1) очистить пользовательский ввод и 2) использовать подготовленные операторы.

Пользовательский ввод

Если вы используете более старую версию PHP (5.5 или ниже, и это часто случается на виртуальном хостинге), было бы целесообразно выполнить весь пользовательский ввод с помощью функции mysql_real_escape_string ().

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

Например, если у вас есть строка, похожая на строку «I’m a strin», злоумышленник может использовать символ одинарной кавычки (‘) для манипулирования создаваемым запросом к базе данных и вызывать SQL-инъекцию.

Запуск его через mysql_real_escape_string () приводит к появлению строки, которая добавляет обратную косую черту к одиночной кавычке, избегая ее.

В результате вся строка теперь передается в базу данных как безвредная строка вместо возможности участвовать в манипулировании запросами.

У этого подхода есть один недостаток: это действительно очень старая техника, которая согласуется со старыми формами доступа к базе данных в PHP.

Начиная с PHP 7, этой функции больше не существует, что подводит нас к следующему решению.

Используйте готовые операторы

Подготовленные операторы – это способ сделать запросы к базе данных более безопасными и надежными.

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

Это то, что мы подразумеваем под «подготовкой».

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

Это отнимает любую особую мощность, которую могут иметь входные данные, в результате чего они будут рассматриваться как простые переменные (или полезные нагрузки, если хотите) во всем процессе.

Вот как выглядят подготовленные операторы:

<?php

$servername = "localhost";

$username = "username";

$password = "password";

$dbname = "myDB";



// Create connection

$conn = new mysqli($servername, $username, $password, $dbname);



// Check connection

if ($conn->connect_error) {

    die("Connection failed: " . $conn->connect_error);

}



// prepare and bind

$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");

$stmt->bind_param("sss", $firstname, $lastname, $email);



// set parameters and execute

$firstname = "John";

$lastname = "Doe";

$email = "john@example.com";

$stmt->execute();



$firstname = "Mary";

$lastname = "Moe";

$email = "mary@example.com";

$stmt->execute();



$firstname = "Julie";

$lastname = "Dooley";

$email = "julie@example.com";

$stmt->execute();



echo "New records created successfully";



$stmt->close();

$conn->close();

?>

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

Для тех, кто уже знаком с расширением PDO PHP и использует его для создания готовых операторов, у меня есть небольшой совет.

Предупреждение: будьте осторожны при настройке PDO

Используя PDO для доступа к базе данных, мы можем впасть в ложное чувство безопасности. «Ах, хорошо, я использую PDO. Теперь мне не нужно думать ни о чем другом », – таково наше мышление.

Это правда, что PDO (или подготовленные MySQLi операторы) достаточно для предотвращения всевозможных SQL-атак, но вы должны быть осторожны при его настройке.

Обычно просто скопируйте и вставьте код из учебников или из ваших предыдущих проектов и двигайтесь дальше, но этот параметр может отменить все:

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

Решение простое: убедитесь, что для этой эмуляции установлено значение false.

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Теперь PHP-скрипт вынужден использовать подготовленные операторы на уровне базы данных, предотвращая всевозможные SQL-инъекции.

Предотвращение SQLi с использованием WAF

Знаете ли вы, что вы также можете защитить веб-приложения от внедрения SQL с помощью WAF (брандмауэр веб-приложений)?

И не только SQL-инъекция, но и многие другие уязвимости уровня 7, такие как межсайтовый скриптинг, неправильная аутентификация, межсайтовая подделка, раскрытие данных и т. д.

Вы можете использовать самодостаточный хостинг, такой как Mod Security, или облачный, как показано ниже.

Заключение

SQL-инъекция – очень неприятная атака на веб-приложение, но ее легко избежать.

Как мы увидели в этой статье, осторожность при обработке пользовательского ввода (кстати, SQL-инъекция – не единственная угроза, которую приносит обработка пользовательского ввода) и запрос базы данных – это все, что нужно сделать.

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

Статьи по теме:

 



2019-06-03T11:42:45
Закрытие уязвимостей