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

Ochrana před SQL Injection v roce 2026: kompletní průvodce od Hostiserver

⏱️ Doba čtení: ~10 minut | 📅 Aktualizováno: 17. prosince 2025

SQL Injection v roce 2026: proč je to stále problém

SQL Injection zůstává v OWASP Top 10 již více než 20 let. V listopadu 2025 OWASP zveřejnil aktualizovaný žebříček, kde Injection zaujímá 5. místo (A05:2025). FBI a CISA oficiálně označily SQLi jako "unforgivable defect" — zranitelnost, která by v moderním softwaru neměla existovat.

Ale existuje. V Hostiserveru to vidíme pravidelně: klienti přicházejí po napadení, s poškozenými databázemi, s úniky uživatelských dat. Ve většině případů je příčinou chybějící prepared statements nebo zastaralý kód bez validace.

Tento průvodce není teoretický přehled. Sestavili jsme konfigurace a přístupy, které skutečně používáme na managed serverech Hostiserver: od nastavení ModSecurity po MySQL hardening. Vše ověřeno v praxi.

⚠️ Důležité: Pokud váš web přijímá jakýkoli uživatelský vstup (formuláře, vyhledávání, filtry, URL parametry) — je potenciálně zranitelný. I "jednoduchý blog" na WordPressu se může stát obětí kvůli zranitelnému pluginu.

Jak funguje SQL Injection

SQL Injection je technika útoku, při které útočník vkládá škodlivý SQL kód do vstupních polí. Pokud aplikace nevaliduje vstup, tento kód se spustí na databázovém serveru.

SQL Injection

Příklad zranitelného kódu

// ❌ NEBEZPEČNÉ — nikdy to nedělejte!
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = mysqli_query($conn, $query);

Pokud útočník zadá do pole username:

' OR '1'='1' --

Dotaz se změní na:

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

Výsledek: útočník získá přístup ke všem záznamům v tabulce.

Typy útoků

Typ Mechanismus Obtížnost detekce
Classic (In-band) Výsledek viditelný na stránce Nízká
Union-based UNION vytahuje data z jiných tabulek Nízká
Error-based Data přes chybové zprávy Střední
Blind SQLi Žádný viditelný výsledek, "hádání" Vysoká
Time-based Blind SLEEP() určuje pravdivost podmínek Vysoká
Out-of-band Data jdou na externí server Velmi vysoká

Aktuální CVE: SQL Injection v letech 2024-2025

SQLi není archaický problém. Kritické zranitelnosti se nacházejí i v moderním enterprise softwaru. Zde je několik příkladů, které sledujeme:

CVE-2025-25257: Fortinet FortiWeb

Ironický případ: SQL Injection v samotném WAF. CVSS 9.6 Critical. Zranitelnost umožňovala neautentizovanému útočníkovi spouštět SQL příkazy přes HTTP požadavky. (Zdroj informací).

CVE-2025-1094: PostgreSQL

Kritická zranitelnost v escapovacích funkcích PostgreSQL. CVSS 8.1 High. Obejití prepared statements přes nesprávné zpracování multibyte znaků. Postihla všechny verze do 17.3. (Zdroj informací).

CVE-2024-42327: Zabbix

CVSS 9.9 Critical. Jakýkoli uživatel s API přístupem mohl využít SQLi a eskalovat oprávnění. Zabbix používají tisíce společností pro monitoring infrastruktury. (Zdroj informací).

MOVEit Transfer (CVE-2023-34362)

Tento případ je stále zmiňován jako ukázka rozsahu problému. SQLi vedla ke kompromitaci více než 2 500 organizací. (Zdroj informací).

Co může útočník udělat

  • Ukrást data — hesla, emaily, platební údaje
  • Změnit data — zfalšovat transakce, změnit ceny
  • Získat shell přístup — přes INTO OUTFILE
  • Zničit databázi — DROP TABLE, TRUNCATE
  • Eskalovat oprávnění — získat admin přístup

Prepared Statements: jediný správný přístup

Prepared Statements (parametrizované dotazy) jsou nejúčinnější ochranou proti SQL Injection. Oddělují SQL kód od dat. Doporučujeme to jako základní standard pro všechny projekty.

PHP PDO (doporučujeme)

// ✅ BEZPEČNÉ — PDO s 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); // Důležité!
$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

// ✅ BEZPEČNÉ — MySQLi s 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();

Proč to funguje

Při použití prepared statements:

  1. SQL dotaz se kompiluje odděleně od dat
  2. Parametry se předávají jako hodnoty, ne jako kód
  3. Speciální znaky se automaticky escapují
  4. I ' OR '1'='1 se stane pouhým řetězcem

✅ Naše doporučení: VŽDY používejte prepared statements pro SQL dotazy s uživatelským vstupem. Bez výjimek.

Důležité: CVE-2025-1094

V únoru 2025 bylo zjištěno, že i prepared statements mohou být obejity při nesprávném zpracování multibyte znaků v PostgreSQL. Řešení je jednoduché: udržujte software aktuální (PostgreSQL 17.3+, 16.7+, 15.11+).

ORM a frameworky: vestavěná ochrana

Moderní frameworky mají ochranu proti SQL Injection "z krabice". Na serverech Hostiserver podporujeme všechny populární frameworky — Laravel, Django, Node.js stack.

Laravel Eloquent (PHP)

// ✅ BEZPEČNÉ — Eloquent automaticky parametrizuje
$users = User::where('username', $username)
             ->where('status', 'active')
             ->get();
// ✅ BEZPEČNÉ — Query Builder
$users = DB::table('users')
           ->where('username', $username)
           ->get();
// ❌ NEBEZPEČNÉ — raw dotazy bez bindings
// DB::select("SELECT * FROM users WHERE username = '$username'");

Django ORM (Python)

# ✅ BEZPEČNÉ — Django ORM
users = User.objects.filter(username=username, status='active')
# ✅ BEZPEČNÉ — raw dotaz s parametry
users = User.objects.raw('SELECT * FROM users WHERE username = %s', [username])
# ❌ NEBEZPEČNÉ — string formatting
# User.objects.raw(f"SELECT * FROM users WHERE username = '{username}'")

Node.js (Sequelize / Prisma)

// ✅ BEZPEČNÉ — Sequelize
const users = await User.findAll({
  where: { username: username, status: 'active' }
});
// ✅ BEZPEČNÉ — Prisma
const users = await prisma.user.findMany({
  where: { username: username, status: 'active' }
});

⚠️ Pozor: ORM chrání pouze při správném použití. Raw SQL uvnitř ORM může být stále zranitelné. Často to vidíme při auditu klientských projektů.

Validace vstupu: dodatečná vrstva

Validace je dodatečná ochrana, ne náhrada za prepared statements. Doporučujeme aplikovat oba přístupy současně.

Typy validace

Typ Popis Příklad
Whitelist Povolujeme pouze očekávané hodnoty Řazení: pouze 'asc' nebo 'desc'
Type casting Vynucená konverze typu $id = (int) $_GET['id'];
Validace formátu Kontrola formátu dat Email, datum, UUID
Omezení délky Omezení délky Username: max 50 znaků

Příklady validace v PHP

// ✅ Whitelist pro řazení (ORDER BY nelze parametrizovat)
$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 pro ID
$user_id = filter_var($_GET['id'], FILTER_VALIDATE_INT);
if ($user_id === false) {
    throw new InvalidArgumentException('Invalid user ID');
}
// ✅ Regex pro specifické formáty
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
    throw new InvalidArgumentException('Invalid username format');
}

💡 Z naší zkušenosti: Whitelist je vždy lepší než Blacklist. Místo blokování nebezpečných znaků — povolujte pouze očekávané.

WAF: jak konfigurujeme na serverech Hostiserver

WAF analyzuje HTTP požadavky a blokuje podezřelé vzory dříve, než se dostanou k aplikaci. Obzvláště důležité pro legacy kód, který je obtížné přepsat.

Co používáme

Řešení Úroveň Použití
ModSecurity Serverový (Apache/Nginx) Hluboká inspekce požadavků
Cloudflare WAF DNS proxy Edge protection, DDoS

ModSecurity pravidla (naše konfigurace)

Zde je příklad pravidel, která konfigurujeme pro klienty:

# Pravidlo 1: Detekce SQLi vzorů
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'"
# Pravidlo 2: Blokování při překročení anomaly score
SecRule TX:INBOUND_ANOMALY_SCORE "@ge 5" \
    "id:1001099,phase:2,deny,status:403,log,msg:'Inbound anomaly score exceeded'"

Co tato pravidla blokují

  • UNION SELECT — vytahování dat z jiných tabulek
  • SLEEP() — time-based blind SQLi
  • BENCHMARK() — alternativní time-based útok
  • OR 1=1 — klasická boolean injection

OWASP Core Rule Set (CRS)

Pro komplexní ochranu instalujeme OWASP CRS — sadu pravidel pokrývající SQLi, XSS, LFI a další útoky:

# Instalace OWASP CRS pro Apache
sudo apt install libapache2-mod-security2
sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
# Stažení CRS
cd /etc/modsecurity
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

✅ Náš přístup: Kombinujeme ModSecurity na serveru s Cloudflare WAF. Cloudflare blokuje většinu útoků na edge, ModSecurity zachytí to, co projde.

MySQL Hardening: naše standardní nastavení

I když útočník najde SQLi, správně nakonfigurovaná databáze minimalizuje škody. Zde je, co děláme na managed serverech Hostiserver.

Síťová izolace

# /etc/mysql/mysql.conf.d/mysqld.cnf
# MySQL naslouchá pouze na localhost — KRITICKÉ!
bind-address = 127.0.0.1
# Port 3306 NENÍ otevřený do veřejného internetu
# Přístup povolen pouze z localhost nebo konkrétních IP přes firewall

Princip minimálních oprávnění

Každá aplikace dostává samostatného uživatele s minimálními právy:

-- ✅ Samostatný uživatel pro aplikaci
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'STRONG_RANDOM_PASSWORD';
-- Pouze potřebná práva na konkrétní databázi
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'localhost';
-- ❌ NEDÁVAT: GRANT ALL ON *.*
-- ❌ NEDÁVAT: SUPER, FILE, PROCESS, SHUTDOWN
FLUSH PRIVILEGES;

Naše standardní politika

Co děláme Jak
Odstraňujeme anonymní uživatele DELETE FROM mysql.user WHERE User='';
Root pouze lokálně Zákaz root@'%'
Silná hesla Password policy, min. 16 znaků
Izolace databází Uživatel vidí pouze svou DB
TLS pro remote REQUIRE SSL

Limity a timeouty

# /etc/mysql/mysql.conf.d/mysqld.cnf
max_connections = 150
max_user_connections = 50
# Timeouty — uzavření idle spojení
wait_timeout = 300
interactive_timeout = 300

⚠️ Proč je to důležité: Pokud útočník najde SQLi, je omezen právy app_user. Bez FILE — nemůže zapisovat soubory. Bez SUPER — nemůže měnit konfiguraci serveru.

Monitoring: jak detekujeme útoky

Preventivní ochrana je důležitá, ale musíte také vidět, co se děje v reálném čase.

MySQL logování

# /etc/mysql/mysql.conf.d/mysqld.cnf
# Error log — vždy zapnutý
log_error = /var/log/mysql/error.log
# Slow query log — detekce podezřelých dotazů
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

Audit logování

Pro compliance a forensics používáme:

  • MariaDB Audit Plugin — zdarma pro MariaDB
  • MySQL Enterprise Audit — pro MySQL Enterprise
# MariaDB Audit Plugin
INSTALL SONAME 'server_audit';
SET GLOBAL server_audit_logging = ON;
SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';

Na co nastavujeme alerty

  • Abnormálně vysoký počet požadavků z jedné IP
  • Dotazy s podezřelými vzory (UNION, SLEEP)
  • Chyby autentizace
  • Změny struktury databáze

SIEM pro Enterprise

Pro enterprise klienty nabízíme integraci s Elastic Security (ELK SIEM) — centralizovaný sběr logů, korelace událostí, automatická detekce hrozeb.

💡 Tip: Slow query log není jen o výkonu. Abnormálně pomalé dotazy mohou indikovat time-based SQLi (SLEEP, BENCHMARK).

Doporučené verze pro rok 2026

Aktualizace verzí PHP/MySQL

Zastaralé verze PHP a MySQL mají známé zranitelnosti. Zde je, co doporučujeme klientům:

PHP

Verze Status Naše doporučení
PHP 8.4 ✅ Active Support Nejlepší volba
PHP 8.3 ✅ Active Support Doporučeno
PHP 8.2 ⚠️ Security Only Minimální verze
PHP 8.1 a nižší ❌ End of Life Urgentně aktualizujte!

MySQL / MariaDB

Verze Status Naše doporučení
MySQL 8.4 LTS ✅ Long Term Support Nejlepší volba
MySQL 8.0.3x+ ✅ Active Support Doporučeno
MariaDB 10.11 LTS ✅ Long Term Support Doporučeno
MySQL 5.7 ❌ End of Life Kritické riziko!

PostgreSQL (po CVE-2025-1094)

Pokud používáte PostgreSQL — aktualizujte na verze 17.3+, 16.7+, 15.11+, 14.16+ nebo 13.19+.

🔴 Kritické: MySQL 5.7 a PHP 7.x již nedostávají bezpečnostní aktualizace. Pokud jste na těchto verzích — kontaktujte nás, pomůžeme s migrací.

Checklist: zkontrolujte svůj projekt

🔐 Kód aplikace

  • ☐ Všechny SQL dotazy používají prepared statements
  • ☐ PDO: ATTR_EMULATE_PREPARES = false
  • ☐ ORM/Query Builder místo raw SQL
  • ☐ Whitelist validace pro ORDER BY, názvy tabulek
  • ☐ Type casting pro číselné parametry
  • ☐ Chybové zprávy nezobrazují SQL dotazy

🛡️ Serverová infrastruktura

  • ☐ WAF (ModSecurity / Cloudflare) aktivní
  • ☐ MySQL bind-address = 127.0.0.1
  • ☐ Port 3306 uzavřený zvenčí
  • ☐ Samostatný databázový uživatel pro každou aplikaci
  • ☐ Minimální oprávnění (SELECT, INSERT, UPDATE, DELETE)
  • ☐ Zakázáno SUPER, FILE, PROCESS

📊 Monitoring

  • ☐ Error log zapnutý
  • ☐ Slow query log zapnutý
  • ☐ Alerty na podezřelou aktivitu

🔄 Údržba

  • ☐ PHP 8.2+ (doporučeno 8.3/8.4)
  • ☐ MySQL 8.0+ / MariaDB 10.11+
  • ☐ PostgreSQL 17.3+ (pokud používáte)
  • ☐ Pravidelné zálohy

🛡️ Potřebujete pomoc se zabezpečením?

Můžeme provést audit vašeho projektu, nakonfigurovat WAF, hardening databáze a monitoring.

Co je součástí managed serverů Hostiserver:

  • ModSecurity WAF s pravidly pro SQLi
  • Cloudflare integrace
  • MySQL hardening podle našich standardů
  • Samostatní databázoví uživatelé
  • Monitoring a alerty
  • Pravidelné zálohy

Pro Enterprise:

  • Elastic Security (ELK SIEM)
  • MySQL Audit Plugin
  • TLS šifrování
  • 24/7 DevOps podpora

FAQ: Často kladené dotazy

Chrání WordPress před SQL Injection?

WordPress core používá $wpdb->prepare() a je dobře chráněný. Ale pluginy a šablony jsou jiný příběh. Z naší zkušenosti většina napadení WordPressu probíhá přes zranitelné pluginy.

Doporučujeme: Používejte ověřené pluginy, pravidelně aktualizujte, nainstalujte WAF.

Chrání prepared statements na 100%?

Prepared statements chrání před injekcí hodnot. Ale některé elementy nelze parametrizovat: názvy tabulek, ORDER BY, LIMIT. Pro ty — whitelist validace.

Také zvažte CVE-2025-1094: PostgreSQL měl zranitelnost v samotných escapovacích funkcích. Udržujte software aktuální.

Stačí pouze WAF?

Ne. WAF je důležitá vrstva, ale ne všelék. CVE-2025-25257 ukázal, že i Fortinet FortiWeb (samotný WAF!) měl kritickou SQLi zranitelnost.

Správný přístup: prepared statements + validace + WAF + database hardening.

PDO nebo MySQLi?

Obě jsou bezpečné při správném použití:

  • PDO — podporuje 12+ databází, pojmenované placeholdery, doporučujeme pro nové projekty
  • MySQLi — pouze MySQL/MariaDB, o něco rychlejší

Důležité pro PDO: ATTR_EMULATE_PREPARES = false.

Jak otestovat web na SQL Injection?

Nástroje:

Důležité: Testujte pouze vlastní weby. Testování cizích bez povolení je trestný čin.

Co dělat, když už došlo k napadení?
  1. Izolujte server od sítě
  2. Vytvořte zálohu pro forensics
  3. Zkontrolujte logy na vstupní bod
  4. Obnovte z čisté zálohy
  5. Opravte zranitelnost
  6. Změňte všechna hesla
  7. Informujte uživatele o úniku

Pokud potřebujete pomoc s incident response — kontaktujte naši podporu.

Je potřeba samostatný databázový uživatel pro každý web?

Ano. Izolace je kritický element. Pokud je napaden jeden web — ostatní databáze zůstanou chráněny. Toto nastavujeme standardně na všech managed serverech.

Contents

MANAGED VPS STARTING AT

$19 95 / mo

NEW INTEL XEON BASED SERVERS

$80 / mo

CDN STARTING AT

$0 / mo

 

Tento web používá cookies. Používáním tohoto webu souhlasíte s politikou ochrany osobních údajů.