Slovník pojmů

SQL injection

SQL injection vzniká, když se vstup uživatele stane součástí SQL kódu. Parametry chrání hodnoty; názvy sloupců a řazení potřebují předem daný whitelist.

Stručná definice

Hodnota nesmí měnit strukturu dotazu.

SQL injection vzniká při skládání SQL řetězce z příkazu a neověřeného vstupu. Databáze pak nedokáže poznat, která část je původně zamýšlená hodnota a která SQL syntaxe. Chyba může vést k nečekanému čtení, změně nebo smazání dat podle práv databázového účtu aplikace.

Prepared statement s placeholderem předá databázi strukturu dotazu a hodnotu odděleně. Hodnota e-mailu, čísla objednávky nebo data proto nemění SQL příkaz. Validace vstupu stále pomáhá business pravidlům a srozumitelným chybám, ale není náhradou parametrizace.

Použití

Kde ochranu hlídat

Riziko se netýká jen veřejného formuláře; vstup může přijít z API, importu, administrace i interního skriptu.

  • filtrování objednávek podle e-mailu, stavu nebo data
  • vyhledávání produktů a exporty administrace
  • API endpointy s parametry, stránkováním a řazením
  • importy externích identifikátorů a integrační reporty
  • ručně psané SQL, DQL fragmenty i dynamické query builder výrazy

Praktický příklad

Filtr objednávek a bezpečné řazení

Následující první řádek ukazuje chybu: e-mail by se přilepil do SQL textu. Bezpečná varianta posílá e-mail jako parametr. Směr řazení a název sloupce se naopak parametrizovat nedají, proto aplikace použije mapu předem povolených voleb a výchozí hodnotu.

Ukázka používá Doctrine DBAL jen pro názornost. Stejný princip platí pro PDO i ORM: data oddělit parametrem, strukturu dotazu určit kódem a neposílat do ní volný text od klienta.

// Nedělat: SQL kód a data jsou v jednom řetězci.
$sql = "SELECT * FROM orders WHERE customer_email = '$email'";

$sortColumns = ['date' => 'created_at', 'number' => 'order_number'];
$sort = $sortColumns[$requestedSort] ?? 'created_at';

$rows = $connection->executeQuery(
    'SELECT id, order_number, created_at
     FROM orders
     WHERE customer_email = :email
     ORDER BY ' . $sort . ' DESC',
    ['email' => $email],
);

Jak funguje

Od vstupu k bezpečnému dotazu

Bezpečný tok rozlišuje hodnotu, kterou lze parametrizovat, od části SQL struktury, kterou musí aplikace sama pevně určit.

  1. Aplikace přijme vstup E-mail, filtr či zvolený směr řazení je nedůvěryhodný, i když pochází z interní administrace.
  2. Rozdělí hodnoty a identifikátory Hodnoty jdou do parametrů; název sloupce, tabulky a SQL klíčové slovo nejsou běžné parametry.
  3. Ověří povolené volby Dynamické řazení se převede přes whitelist, například created_at nebo order_number, nikdy nepřilepí přímo z requestu.
  4. Provádí prepared statement DBAL, PDO nebo ORM předají typovanou hodnotu přes placeholder a databáze zachová strukturu dotazu.
  5. Omezí následky chyby Databázový účet má jen nutná práva a klient dostane bezpečnou chybovou odpověď bez SQL detailů.

Důležité pojmy

Bezpečnost je v rozhraní mezi SQL a daty.

Každá technika chrání jinou část problému; žádná sama neřeší všechna business pravidla.

Prepared statements a placeholdery

Placeholder :email nebo ? zastupuje hodnotu. Driver ji pošle databázi odděleně od SQL textu a správně zpracuje podle typu. Ruční escapování řetězce je křehčí a není náhradou.

Whitelist identifikátorů

Název sloupce, tabulky nebo ASC/DESC obvykle nelze předat jako parametr. Aplikace vybírá z pevně definované mapy známých možností, nikoli z volného textu requestu.

ORM a QueryBuilder

Doctrine ORM a DBAL snižují riziko při práci s parametry, ale ručně složené SQL/DQL fragmenty nebo Expression mohou chybu znovu otevřít. QueryBuilder není automaticky bezpečný řetězec.

Nejmenší databázová oprávnění

Aplikační účet má mít jen práva potřebná pro provoz. Neodstraní chybu v dotazu, ale omezuje, co lze při jejím zneužití provést.

Vztah k podobným pojmům

SQL injection není XSS ani problém vyřešený jen ORM.

Přesné rozlišení pomáhá zvolit správnou obranu na správné straně aplikace.

Doctrine DBAL
Nabízí parametrizované SQL, transakce a query builder. Správné použití parametrů zůstává odpovědností aplikačního kódu.
Doctrine ORM
Mapuje entity a běžné dotazy často parametrizuje. Nechrání libovolné nativní SQL či ručně sestavenou část DQL.
Validace a escapování
Validace kontroluje povolený business formát, escapování řeší konkrétní kontext výstupu. Pro SQL hodnoty je základ parametrizace.
XSS
XSS vykonává vložený kód v prohlížeči; SQL injection mění databázový dotaz na serveru. Mají jiné vektory i obrany.

Výhody a omezení

Správný mechanismus je jednoduchý, hranice dotazu musí být promyšlená.

Přínosy

  • parametry jednoznačně oddělí data od SQL syntaxe
  • whitelist dává bezpečný a čitelný výběr řazení či sloupců
  • DBAL, PDO a ORM podporují standardní bezpečnou cestu
  • omezená databázová práva zmenší následky další chyby

Rizika a chyby

  • ruční konkatenace i po escapování se snadno rozbije při změně kontextu
  • ORM nechrání nativní SQL ani dynamické fragmenty automaticky
  • parametr nelze použít místo názvu tabulky, sloupce či SQL klíčového slova
  • WAF může útok zachytit, ale nenahrazuje opravu zdrojového kódu

Hranice použití

Parametrizace je výchozí, ne volitelný detail.

Každá hodnota pocházející mimo pevně napsaný SQL příkaz patří do parametru. To platí i pro čísla, datum, API payload či data z dřívějšího importu: dnešní interní hodnota může být zítřejší neověřený vstup. Jednotné databázové rozhraní a code review pomáhají nebezpečnou konkatenaci zachytit včas.

Dynamické řazení, název sloupce nebo směr sortu jsou jiný případ. Je-li potřebujete měnit, návrh má vytvořit mapu povolených hodnot a vybrat pouze z ní. Nikdy není cílem umožnit klientovi psát SQL; cílem je nabídnout malou, jasně definovanou množinu funkcí aplikace.

Na co myslet

Ochranu ověřovat v kódu i oprávněních databáze.

Bezpečné dotazy mají být běžnou cestou, ne rozhodnutím každého jednotlivého vývojáře.

  • parametrizovat každou dynamickou hodnotu v SQL, DQL i query builderu
  • pro řazení, sloupce a tabulky používat pevný whitelist
  • nevracet klientovi databázovou chybu, SQL text ani stack trace
  • dávat aplikaci minimální nutná databázová oprávnění
  • testovat filtrování a řazení včetně neočekávaných vstupů a kontrolovat ruční SQL v review

Časté otázky

Co parametrizace chrání a co ne

Stačí validovat e-mail nebo číslo?

Ne. Validace je užitečná pro business pravidla, ale bezpečné oddělení hodnoty od SQL kódu zajišťuje parametrizovaný dotaz.

Mohu parametrizovat název sloupce v ORDER BY?

Obvykle ne. Placeholder je pro hodnotu, ne pro SQL identifikátor. Použijte mapu povolených názvů a vyberte pouze z ní.

Jsem v bezpečí, když používám ORM?

Běžná práce s entitami a parametry riziko výrazně snižuje. Ručně složené native SQL, DQL fragmenty nebo nebezpečné expression mohou SQL injection znovu umožnit.

Vyřeší problém web application firewall?

Může zachytit část pokusů, ale nemůže spolehlivě nahradit parametrizaci v aplikaci. Oprava patří do kódu a databázových oprávnění.

Jak pracuji s daty v praxi

Databázové dotazy posuzuji spolu s integritou a oprávněním.

Při vývoji backendů řeším explicitní SQL, ORM, transakce, constrainty i bezpečnou hranici mezi HTTP vstupem a databází.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.