Sheensay → Вебразработка → Как избежать SQL инъекций в PHP

Как избежать SQL инъекций в PHP

03.05.2019

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

// Никак не обрабатываем данные, получаемые от пользователей
$unsafe_variable = $_POST['user_input']; 

// Затем эти данные отправляем в базу данных
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

Опасность тут заключается в следующем: если пользователь отправит данные вроде таких: value'); DROP TABLE table_name;--, то итоговый запрос будет выглядеть так:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table_name;--')

Этот запрос удалит таблицу table_name.

Чтобы избежать подобной проблемы, можно воспользоваться следующими рекомендациями:

Использовать заранее подготовленные данные

Можно воспользоваться подготовленными операторами и обработанными таким образом запросами. Такие операторы SQL позволят вам определять типы передаваемых данных, фильтровать их.

Есть 2 варианта их использования:

  1. Используем PDO (PHP Data Objects):
    // Конфигурируем будущий запрос,
    $q = $pdo->prepare('SELECT * FROM table_name WHERE name = :name');
    
    // Выполняем запрос, установив связь с введёнными данными
    // $name - переменная с данными, которые связываются с оператором name
    $q->execute(array('name' => $name));
    
    foreach ($q as $e) {
        // Производим манипуляции с результатами $e
    }
    
  2. Для MySQL используем MySQLi
    $q = $db->prepare('SELECT * FROM table_name WHERE name = ?');
    // $name - переменная с данными, которые будут обрабатываться
    $q->bind_param('s', $name); // 's' определяет тип переменной => 'string' (строка)
    
    $q->execute();
    
    $result = $q->get_result();
    while ($row = $result->fetch_assoc()) {
        // Производим манипуляции с $row
    }
    

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

Например, в PostgreSQL есть pg_prepare() and pg_execute().

Установить соединение с базой данных правильно

PDO по умолчанию эмулирует работу с подготовленными операторами для работы с MySQL. Поэтому важно отключить режим эмуляции, например так:

// Устанавливаем соединение
$db = new PDO('mysql:dbname=mydatabase;host=127.0.0.1;charset=utf8', 'db_login', 'db_pass');

// Отключаем режим эмуляции для обработки данных
// Включаем рабочий реальный режим работы PDO
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

// Включаем режим обработки ошибок и исключений
// PHP Fatal error не будут обрывать работу скрипта, а исключения позволят отлавливать ошибки
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Готовим операторы // :column
$q = $db->prepare('INSERT INTO table (column) VALUES (:column)');

// Связываем операторы с потенциально опасными данными
// которые будут обработаны и отфильтрованы
$q->execute(array('column' => $danger_data));

Важный момент касаемо параметра charset: версии PHP < 5.3.6 молча игнорируют его

Как это всё работает

Указывая параметр ? или именованный :name из примера выше, можно сообщить базе данных, что из данных должно быть обработано и отфильтровано. Затем во время вызова execute() указываются данные, которые будут проверяться.

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

Ещё одно неоспоримое преимущество PDO состоит в том, что если использовать оператор несколько раз в коде, то он скомпилируется 1 раз, а в дальнейшем будет использоваться ранее скомпилированная версия, что даст экономию по ресурсам и увеличит быстродействие скрипта.

Как использовать с динамическими запросами

Вы можете использовать следующий подход (составить белый лист параметов и пропускать только их):

// $order может быть 'DESC' 
// Во всех остальных случаях $order это 'ASC'
if (empty($order) || $order !== 'DESC') {
   $order = 'ASC';
}



Так себеНеплохоНормальноХорошоОтлично (1 оценок, в среднем: 5,00 из 5)
Загрузка...


  • WP-CLI — управление WordPress из консоли
  • WordPress ошибка: требуется обновление базы данных
  • HTTP — заголовки. Что это такое и зачем они нужны
  • Как в htaccess запретить доступ по IP диапазону
  • Как правильно перенести WordPress

Вебразработка

Свежие записи

  • Squid — свой собственный HTTP Proxy сервер
  • Как исправить ошибку «Обновить WordPress — В настоящий момент выполняется другое обновление»
  • Query Monitor
  • LEMP
  • Telegram

Свежие записи

  • Squid — свой собственный HTTP Proxy сервер
  • Как исправить ошибку «Обновить WordPress — В настоящий момент выполняется другое обновление»
  • Query Monitor
  • LEMP
  • Telegram

Свежие комментарии

  • Sheens к записи Что такое SSL и TLS, как установить и настроить
  • Геомант к записи Что такое SSL и TLS, как установить и настроить
  • Sheens к записи Last-Modified в WordPress
  • Артур к записи Last-Modified в WordPress
  • Sheens к записи EWWW Image Optimizer — плагин для сжатия png, jpeg, gif анимации без потери качества
  • Telegram
  • Вконтакте
  • Facebook
  • Twitter
  • Google+
  • Одноклассники
  • Мой Мир Mail.ru
  • RSS

Copyright © 2025 · Sheensay on Genesis Framework · WordPress · Log in