Community
0 59
HostiServer
2025-12-17 09:00:00

Захист від SQL Injection у 2026: повний гайд від Hostiserver

⏱️ Час читання: ~10 хвилин | 📅 Оновлено: 17 грудня 2025

SQL Injection у 2026: чому це досі проблема

SQL Injection залишається в OWASP Top 10 вже понад 20 років. У листопаді 2025 OWASP опублікував оновлений рейтинг, де Injection посідає 5-те місце (A05:2025). FBI та CISA офіційно визнали SQLi "unforgivable defect" — вразливістю, яка не повинна існувати в сучасному софті.

Але вона існує. І ми в Hostiserver бачимо це регулярно: клієнти приходять після зламу, з пошкодженими базами, витоком даних користувачів. У більшості випадків причина — відсутність prepared statements або застарілий код без валідації.

Цей гайд — не теоретичний огляд. Ми зібрали конфігурації та підходи, які реально використовуємо на managed серверах Hostiserver: від налаштування ModSecurity до MySQL hardening. Все перевірено на практиці.

⚠️ Важливо: Якщо ваш сайт приймає будь-який user input (форми, пошук, фільтри, URL-параметри) — він потенційно вразливий. Навіть "простий блог" на WordPress може стати жертвою через вразливий плагін.

Як працює SQL Injection

SQL Injection — техніка атаки, при якій зловмисник вставляє шкідливий SQL-код у поля введення. Якщо застосунок не валідує input, цей код виконується на сервері бази даних.

SQL Injection

Приклад вразливого коду

// ❌ НЕБЕЗПЕЧНО — ніколи так не робіть!
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = mysqli_query($conn, $query);

Якщо зловмисник введе в поле username:

' OR '1'='1' --

Запит перетвориться на:

SELECT * FROM users WHERE username = '' OR '1'='1' --'

Результат: зловмисник отримує доступ до всіх записів таблиці.

Типи атак

Тип Механізм Складність виявлення
Classic (In-band) Результат видно на сторінці Низька
Union-based UNION витягує дані з інших таблиць Низька
Error-based Дані через повідомлення про помилки Середня
Blind SQLi Немає видимого результату, "вгадування" Висока
Time-based Blind SLEEP() визначає істинність умов Висока
Out-of-band Дані йдуть на зовнішній сервер Дуже висока

Свіжі CVE: SQL Injection у 2024-2025

SQLi — не архаїчна проблема. Критичні вразливості знаходять навіть у сучасному enterprise-софті. Ось кілька прикладів, які ми відстежували:

CVE-2025-25257: Fortinet FortiWeb

Іронічний кейс: SQL Injection у самому WAF. CVSS 9.6 Critical. Вразливість дозволяла неавтентифікованому атакуючому виконувати SQL-команди через HTTP-запити. (Джерело інформації).

CVE-2025-1094: PostgreSQL

Критична вразливість у функціях екранування PostgreSQL. CVSS 8.1 High. Обхід prepared statements через некоректну обробку multibyte-символів. Зачепила всі версії до 17.3. (Джерело інформації).

CVE-2024-42327: Zabbix

CVSS 9.9 Critical. Будь-який користувач з API-доступом міг експлуатувати SQLi та ескалювати привілеї. Zabbix використовують тисячі компаній для моніторингу інфраструктури. (Джерело інформації).

MOVEit Transfer (CVE-2023-34362)

Цей кейс досі згадують як приклад масштабу проблеми. SQLi призвела до компрометації понад 2,500 організацій. (Джерело інформації).

Що може зробити атакуючий

  • Викрасти дані — паролі, email, платіжні дані
  • Змінити дані — підробити транзакції, змінити ціни
  • Отримати shell-доступ — через INTO OUTFILE
  • Знищити базу — DROP TABLE, TRUNCATE
  • Ескалювати привілеї — отримати admin-доступ

Prepared Statements: єдиний правильний підхід

Prepared Statements (параметризовані запити) — найефективніший захист від SQL Injection. Вони відокремлюють SQL-код від даних. Ми рекомендуємо це як базовий стандарт для всіх проєктів.

PHP PDO (рекомендуємо)

// ✅ БЕЗПЕЧНО — PDO з prepared statements
$pdo = new PDO('mysql:host=localhost;dbname=app_db;charset=utf8mb4', $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // Важливо!
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username AND status = :status');
$stmt->execute([
    ':username' => $username,
    ':status' => 'active'
]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

PHP MySQLi

// ✅ БЕЗПЕЧНО — MySQLi з prepared statements
$mysqli = new mysqli('localhost', $user, $pass, 'app_db');
$mysqli->set_charset('utf8mb4');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE username = ? AND status = ?');
$stmt->bind_param('ss', $username, $status);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

Чому це працює

При використанні prepared statements:

  1. SQL-запит компілюється окремо від даних
  2. Параметри передаються як значення, а не як код
  3. Спеціальні символи автоматично екрануються
  4. Навіть ' OR '1'='1 стає просто рядком

✅ Наша рекомендація: ЗАВЖДИ використовуйте prepared statements для SQL-запитів з user input. Без винятків.

Важливо: CVE-2025-1094

У лютому 2025 виявили, що навіть prepared statements можуть бути обійдені при некоректній обробці multibyte-символів у PostgreSQL. Рішення просте: тримайте софт оновленим (PostgreSQL 17.3+, 16.7+, 15.11+).

ORM та фреймворки: вбудований захист

Сучасні фреймворки мають захист від SQL Injection "з коробки". На серверах Hostiserver ми підтримуємо всі популярні фреймворки — Laravel, Django, Node.js стек.

Laravel Eloquent (PHP)

// ✅ БЕЗПЕЧНО — Eloquent автоматично параметризує
$users = User::where('username', $username)
             ->where('status', 'active')
             ->get();
// ✅ БЕЗПЕЧНО — Query Builder
$users = DB::table('users')
           ->where('username', $username)
           ->get();
// ❌ НЕБЕЗПЕЧНО — raw запити без bindings
// DB::select("SELECT * FROM users WHERE username = '$username'");

Django ORM (Python)

# ✅ БЕЗПЕЧНО — Django ORM
users = User.objects.filter(username=username, status='active')
# ✅ БЕЗПЕЧНО — raw query з параметрами
users = User.objects.raw('SELECT * FROM users WHERE username = %s', [username])
# ❌ НЕБЕЗПЕЧНО — string formatting
# User.objects.raw(f"SELECT * FROM users WHERE username = '{username}'")

Node.js (Sequelize / Prisma)

// ✅ БЕЗПЕЧНО — Sequelize
const users = await User.findAll({
  where: { username: username, status: 'active' }
});
// ✅ БЕЗПЕЧНО — Prisma
const users = await prisma.user.findMany({
  where: { username: username, status: 'active' }
});

⚠️ Увага: ORM захищає тільки при правильному використанні. Raw SQL всередині ORM все ще може бути вразливим. Ми часто бачимо це при аудиті клієнтських проєктів.

Input Validation: додатковий рівень

Валідація — це додатковий захист, а не заміна prepared statements. Ми рекомендуємо застосовувати обидва підходи одночасно.

Типи валідації

Тип Опис Приклад
Whitelist Дозволяємо тільки очікувані значення Сортування: тільки 'asc' або 'desc'
Type casting Примусове перетворення типу $id = (int) $_GET['id'];
Format validation Перевірка формату даних Email, дата, UUID
Length limits Обмеження довжини Username: max 50 символів

Приклади валідації в PHP

// ✅ Whitelist для сортування (ORDER BY не параметризується)
$allowed_columns = ['created_at', 'username', 'email'];
$sort_column = in_array($_GET['sort'], $allowed_columns) ? $_GET['sort'] : 'created_at';
$allowed_directions = ['ASC', 'DESC'];
$sort_dir = in_array(strtoupper($_GET['dir']), $allowed_directions) ? strtoupper($_GET['dir']) : 'DESC';
// ✅ Type casting для ID
$user_id = filter_var($_GET['id'], FILTER_VALIDATE_INT);
if ($user_id === false) {
    throw new InvalidArgumentException('Invalid user ID');
}
// ✅ Regex для специфічних форматів
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
    throw new InvalidArgumentException('Invalid username format');
}

💡 З нашого досвіду: Whitelist завжди краще за Blacklist. Замість блокування небезпечних символів — дозволяйте тільки очікувані.

WAF: як ми налаштовуємо на серверах Hostiserver

WAF аналізує HTTP-запити і блокує підозрілі патерни до того, як вони досягнуть застосунку. Особливо важливо для legacy-коду, який складно переписати.

Що ми використовуємо

Рішення Рівень Застосування
ModSecurity Серверний (Apache/Nginx) Глибока інспекція запитів
Cloudflare WAF DNS-проксі Edge protection, DDoS

ModSecurity правила (наша конфігурація)

Ось приклад правил, які ми налаштовуємо для клієнтів:

# Правило 1: Виявлення SQLi патернів
SecRule ARGS|REQUEST_BODY \
    "@rx (?i)(union\s+select|sleep\(|benchmark\(|or\s+1=1)" \
    "id:1001002,phase:2,pass,log,tag:'attack-sqli',setvar:'tx.inbound_anomaly_score=+5',msg:'SQLi pattern detected'"
# Правило 2: Блокування при перевищенні anomaly score
SecRule TX:INBOUND_ANOMALY_SCORE "@ge 5" \
    "id:1001099,phase:2,deny,status:403,log,msg:'Inbound anomaly score exceeded'"

Що блокують ці правила

  • UNION SELECT — витягування даних з інших таблиць
  • SLEEP() — time-based blind SQLi
  • BENCHMARK() — альтернативна time-based атака
  • OR 1=1 — класична boolean injection

OWASP Core Rule Set (CRS)

Для повноцінного захисту ми встановлюємо OWASP CRS — набір правил, що покриває SQLi, XSS, LFI та інші атаки:

# Встановлення OWASP CRS для Apache
sudo apt install libapache2-mod-security2
sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
# Завантажити CRS
cd /etc/modsecurity
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

✅ Наш підхід: Комбінуємо ModSecurity на сервері з Cloudflare WAF. Cloudflare блокує основну масу атак на edge, ModSecurity — те, що пройшло.

MySQL Hardening: наші стандартні налаштування

Навіть якщо атакуючий знайде SQLi, правильно налаштована база мінімізує шкоду. Ось що ми робимо на managed серверах Hostiserver.

Мережева ізоляція

# /etc/mysql/mysql.conf.d/mysqld.cnf
# MySQL слухає тільки localhost — КРИТИЧНО!
bind-address = 127.0.0.1
# Порт 3306 НЕ відкритий у публічний інтернет
# Доступ дозволений тільки з localhost або конкретних IP через firewall

Принцип мінімальних привілеїв

Кожен застосунок отримує окремого користувача з мінімальними правами:

-- ✅ Окремий користувач для застосунку
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'STRONG_RANDOM_PASSWORD';
-- Тільки необхідні права на конкретну базу
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'localhost';
-- ❌ НЕ даємо: GRANT ALL ON *.*
-- ❌ НЕ даємо: SUPER, FILE, PROCESS, SHUTDOWN
FLUSH PRIVILEGES;

Наша стандартна політика

Що робимо Як
Видаляємо анонімних користувачів DELETE FROM mysql.user WHERE User='';
Root тільки локально Заборона root@'%'
Сильні паролі Password policy, мін. 16 символів
Ізоляція баз Користувач бачить тільки свою БД
TLS для remote REQUIRE SSL

Ліміти та таймаути

# /etc/mysql/mysql.conf.d/mysqld.cnf
max_connections = 150
max_user_connections = 50
# Таймаути — закриття idle з'єднань
wait_timeout = 300
interactive_timeout = 300

⚠️ Чому це важливо: Якщо атакуючий знайде SQLi, він буде обмежений правами app_user. Без FILE — не зможе писати файли. Без SUPER — не змінить конфігурацію сервера.

Моніторинг: як ми виявляємо атаки

Превентивний захист важливий, але потрібно також бачити, що відбувається в реальному часі.

MySQL логування

# /etc/mysql/mysql.conf.d/mysqld.cnf
# Error log — завжди увімкнено
log_error = /var/log/mysql/error.log
# Slow query log — виявлення підозрілих запитів
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

Audit logging

Для compliance та forensics ми використовуємо:

  • MariaDB Audit Plugin — безкоштовний для MariaDB
  • MySQL Enterprise Audit — для MySQL Enterprise
# MariaDB Audit Plugin
INSTALL SONAME 'server_audit';
SET GLOBAL server_audit_logging = ON;
SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';

На що налаштовуємо alerts

  • Аномально велика кількість запитів з одного IP
  • Запити з підозрілими патернами (UNION, SLEEP)
  • Помилки автентифікації
  • Зміни структури бази даних

SIEM для Enterprise

Для enterprise клієнтів пропонуємо інтеграцію з Elastic Security (ELK SIEM) — централізований збір логів, кореляція подій, автоматичне виявлення загроз.

💡 Порада: Slow query log — не тільки про performance. Аномально повільні запити можуть бути ознакою time-based SQLi (SLEEP, BENCHMARK).

Рекомендовані версії на 2026 рік

Оновлення версій PHP/MySQL

Застарілі версії PHP та MySQL мають відомі вразливості. Ось що ми рекомендуємо клієнтам:

PHP

Версія Статус Наша рекомендація
PHP 8.4 ✅ Active Support Найкращий вибір
PHP 8.3 ✅ Active Support Рекомендовано
PHP 8.2 ⚠️ Security Only Мінімальна версія
PHP 8.1 та нижче ❌ End of Life Терміново оновлюйте!

MySQL / MariaDB

Версія Статус Наша рекомендація
MySQL 8.4 LTS ✅ Long Term Support Найкращий вибір
MySQL 8.0.3x+ ✅ Active Support Рекомендовано
MariaDB 10.11 LTS ✅ Long Term Support Рекомендовано
MySQL 5.7 ❌ End of Life Критичний ризик!

PostgreSQL (після CVE-2025-1094)

Якщо використовуєте PostgreSQL — оновіть до версій 17.3+, 16.7+, 15.11+, 14.16+, або 13.19+.

🔴 Критично: MySQL 5.7 та PHP 7.x більше не отримують security updates. Якщо ви на цих версіях — зверніться до нас, допоможемо з міграцією.

Checklist: перевірте свій проєкт

🔐 Код застосунку

  • ☐ Всі SQL-запити використовують prepared statements
  • ☐ PDO: ATTR_EMULATE_PREPARES = false
  • ☐ ORM/Query Builder замість raw SQL
  • ☐ Whitelist валідація для ORDER BY, назв таблиць
  • ☐ Type casting для числових параметрів
  • ☐ Error messages не показують SQL-запити

🛡️ Серверна інфраструктура

  • ☐ WAF (ModSecurity / Cloudflare) активний
  • ☐ MySQL bind-address = 127.0.0.1
  • ☐ Порт 3306 закритий ззовні
  • ☐ Окремий database user для кожного застосунку
  • ☐ Мінімальні привілеї (SELECT, INSERT, UPDATE, DELETE)
  • ☐ Заборонено SUPER, FILE, PROCESS

📊 Моніторинг

  • ☐ Error log увімкнено
  • ☐ Slow query log увімкнено
  • ☐ Alerts на підозрілу активність

🔄 Maintenance

  • ☐ PHP 8.2+ (рекомендовано 8.3/8.4)
  • ☐ MySQL 8.0+ / MariaDB 10.11+
  • ☐ PostgreSQL 17.3+ (якщо використовуєте)
  • ☐ Регулярні бекапи

🛡️ Потрібна допомога з безпекою?

Ми можемо провести аудит вашого проєкту, налаштувати WAF, hardening бази даних та моніторинг.

Що входить в managed сервери Hostiserver:

  • ModSecurity WAF з правилами для SQLi
  • Cloudflare інтеграція
  • MySQL hardening за нашими стандартами
  • Окремі database користувачі
  • Моніторинг та alerts
  • Регулярні бекапи

Для Enterprise:

  • Elastic Security (ELK SIEM)
  • MySQL Audit Plugin
  • TLS encryption
  • 24/7 DevOps підтримка

FAQ: Часті питання

Чи захищає WordPress від SQL Injection?

WordPress core використовує $wpdb->prepare() і добре захищений. Але плагіни та теми — інша історія. За нашим досвідом, більшість зламів WordPress відбувається саме через вразливі плагіни.

Рекомендуємо: Використовуйте перевірені плагіни, регулярно оновлюйте, встановіть WAF.

Prepared statements захищають на 100%?

Prepared statements захищають від ін'єкції значень. Але є елементи, які не параметризуються: назви таблиць, ORDER BY, LIMIT. Для них — whitelist валідація.

Також враховуйте CVE-2025-1094: PostgreSQL мав вразливість в самих функціях екранування. Тримайте софт оновленим.

Чи достатньо тільки WAF?

Ні. WAF — важливий рівень, але не панацея. CVE-2025-25257 показав, що навіть Fortinet FortiWeb (сам WAF!) мав критичну SQLi вразливість.

Правильний підхід: prepared statements + validation + WAF + database hardening.

PDO чи MySQLi?

Обидва безпечні при правильному використанні:

  • PDO — підтримує 12+ СУБД, іменовані placeholders, рекомендуємо для нових проєктів
  • MySQLi — тільки MySQL/MariaDB, трохи швидший

Важливо для PDO: ATTR_EMULATE_PREPARES = false.

Як перевірити сайт на SQL Injection?

Інструменти:

  • SQLMap — автоматизований тестер
  • Burp Suite — intercepting proxy
  • OWASP ZAP — безкоштовний сканер

Важливо: Тестуйте тільки власні сайти. Тестування чужих без дозволу — злочин.

Що робити, якщо вже зламали?
  1. Ізолюйте сервер від мережі
  2. Зробіть backup для forensics
  3. Перевірте логи на точку входу
  4. Відновіть з чистого backup
  5. Виправте вразливість
  6. Змініть всі паролі
  7. Повідомте користувачів про витік

Якщо потрібна допомога з incident response — звертайтесь до нашої підтримки.

Чи потрібен окремий database user для кожного сайту?

Так. Ізоляція — критичний елемент. Зламають один сайт — інші бази залишаться захищеними. Ми налаштовуємо це за замовчуванням на всіх managed серверах.

Contents

VPS з підтримкою від

$19 95 / міс

Виділені сервери від

$80 / міс

CDN починаючи від

$0 / міс

 

Користуючись цим сайтом, ви погоджуєтеся на використання файлів cookies відповідно до нашої Політики Конфіденційності.