← Назад к вопросам

Какие методы позволяют избежать SQL-инъекций?

2.0 Middle🔥 271 комментариев
#Базы данных и SQL#Безопасность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Методы защиты от SQL-инъекций в PHP

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

1. Использование подготовленных выражений (Prepared Statements)

Это наиболее эффективный и рекомендуемый метод. Суть в том, что SQL-запрос и данные отправляются в СУБД раздельно, что исключает интерпретацию данных как части команды.

С PDO (PHP Data Objects)

// Создание подключения
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // Важно отключить эмуляцию

// Подготовка запроса с плейсхолдерами
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');

// Привязка значений к параметрам с явным указанием типа
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_INT);

// Выполнение
$stmt->execute();
$result = $stmt->fetchAll();

С MySQLi

$mysqli = new mysqli('localhost', 'user', 'password', 'test');

// Подготовка запроса
$stmt = $mysqli->prepare('SELECT * FROM products WHERE category_id = ? AND price > ?');
$stmt->bind_param('id', $category_id, $min_price); // 'i' - integer, 'd' - double
$stmt->execute();
$result = $stmt->get_result();

2. Практика "белого списка" (Whitelisting) для динамических частей запроса

Для параметров, которые не могут быть переданы через подготовленные выражения (например, имена таблиц или столбцов), используйте строгий белый список допустимых значений:

// Допустимые значения для сортировки
$allowed_columns = ['name', 'price', 'created_at'];
$allowed_orders = ['ASC', 'DESC'];

$column = in_array($_GET['sort'], $allowed_columns) ? $_GET['sort'] : 'created_at';
$order = in_array(strtoupper($_GET['order']), $allowed_orders) ? strtoupper($_GET['order']) : 'DESC';

$query = "SELECT * FROM products ORDER BY {$column} {$order}";
// Теперь $column и $order безопасны, так как проверены через белый список

3. Экранирование специальных символов

Менее предпочтительный, но иногда необходимый метод (например, при работе с устаревшим кодом). Используйте специфичные для СУБД функции экранирования:

// Для MySQLi
$escaped_string = $mysqli->real_escape_string($user_input);
$query = "SELECT * FROM comments WHERE text LIKE '%{$escaped_string}%'";

// Для PDO (лучше использовать подготовленные выражения!)
// Иногда применяется для LIKE с подстановочными знаками
$search = '%' . $pdo->quote($user_input) . '%';

4. Валидация и фильтрация входных данных

Всегда проверяйте входные данные на соответствие ожидаемому формату:

// Для числовых значений
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT);
if ($id === false) {
    die('Неверный идентификатор');
}

// Для email
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) {
    die('Неверный формат email');
}

// Санитизация строк
$clean_string = filter_var($input, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

5. Принцип минимальных привилегий

Настройте подключение к БД с использованием учётной записи с минимально необходимыми правами. Если приложению нужно только читать данные, используйте пользователя с правами только на SELECT.

6. Дополнительные меры безопасности

  • Хранимые процедуры — могут помочь, но требуют правильной реализации
  • ORM-библиотеки (Doctrine, Eloquent) — обычно используют подготовленные выражения внутренне
  • Регулярное обновление ПО — как PHP, так и СУБД
  • Логирование и мониторинг подозрительных запросов

Важные принципы:

  • Никогда не доверяйте пользовательскому вводу — все данные считаются потенциально опасными
  • Комбинируйте методы защиты — например, подготовленные выражения + валидация
  • Избегайте динамической конкатенации SQL-запросов — это основной источник уязвимостей
  • Отключите эмуляцию подготовленных выражений в PDOPDO::ATTR_EMULATE_PREPARES => false

Подготовленные выражения остаются "золотым стандартом" защиты, поскольку они корректно обрабатывают все типы данных (строки, числа, даты) и обеспечивают чёткое разделение кода и данных на уровне протокола взаимодействия с СУБД.