Co je SQL Injection a jak se mu bránit

Autor: Zveřejněno

Stručně: SQL Injection je zranitelnost, která umožňuje změnit chování databázového dotazu pomocí vhodně připravených vstupních dat. Vzniká především tehdy, když aplikace spojuje příkazy SQL s textem zadaným uživatelem. Základní ochranou jsou parametrizované dotazy, které oddělují samotný příkaz od jeho dat.

Jak se z uživatelských dat stane příkaz

SQL je jazyk používaný ke čtení a změnám dat v relačních databázích. Aplikace s jeho pomocí může vyhledat účet, načíst objednávku nebo uložit novou adresu zákazníka. SQL Injection neboli vložení příkazu SQL nastává, když se vstupní data vyhodnotí jako součást syntaxe takového příkazu.

Představme si, že aplikace vyhledává účet podle přihlašovacího jména. Programátor napíše začátek dotazu, připojí hodnotu z formuláře a uzavře ji apostrofem. Běžné přihlašovací jméno vrátí očekávaný výsledek, ale text obsahující apostrof a další podmínku může změnit význam celého vyhledávání.

Zdrojem nebezpečné hodnoty nemusí být přihlašovací formulář. Může jím být také parametr adresy URL, filtr produktů, hlavička požadavku nebo data dříve uložená v databázi. Rozhodující je, jak aplikace tuto hodnotu použije, nikoli odkud ji získala.

Jednoduchý pokus v systému Linux

Následující příklad pracuje pouze s dočasnou databází v paměti procesu. Nepřipojuje se k žádnému webu ani externímu serveru. Ukazuje načtení záznamů navíc, nikoli úplný přihlašovací mechanismus.

Potřebujete Python 3 s dostupným modulem sqlite3. Jeho dostupnost ověříte v terminálu příkazem:

python3 -c "import sqlite3; print(sqlite3.sqlite_version)"

Pokud příkaz selže, vyhledejte postup instalace jazyka Python 3 nebo chybějícího modulu v dokumentaci své distribuce. Samostatný databázový server spouštět nemusíte.

Spusťte v terminálu celý blok:

python3 - <<'PY'
import sqlite3

pripojeni = sqlite3.connect(":memory:")
polaczenie.execute(
    "CREATE TABLE ucty (id INTEGER PRIMARY KEY, login TEXT)"
)
polaczenie.executemany(
    "INSERT INTO ucty (login) VALUES (?)",
    [("anna",), ("petr",)]
)

hodnota = "' OR 1=1 -- "
dotaz = "SELECT id, login FROM ucty WHERE login = '" + hodnota + "'"

print("Dotaz:", dotaz)
print("Výsledek:", polaczenie.execute(dotaz).fetchall())
polaczenie.close()
PY

Výsledek obsahuje oba účty, přestože ani jeden nemá přihlašovací jméno odpovídající zadané hodnotě. Apostrof uzavře text přihlašovacího jména, OR 1=1 přidá podmínku, která platí vždy, a -- zahájí komentář. Závěrečný apostrof tak už dotaz neovlivní.

Jde o záměrně zranitelný kód pro místní demonstraci. Podobné vstupy nezkoušejte na cizích webech bez výslovného souhlasu, který zahrnuje rozsah testování.

Jak stejný kód opravit

Parametrizovaný dotaz obsahuje zástupné symboly pro data a samotné hodnoty se předávají odděleně knihovně pro práci s databází. V modulu sqlite3 může být takovým symbolem ?. Knihovna zpracuje předanou hodnotu jako data, nikoli jako další syntaxi SQL.

V předchozím příkladu nahraďte sestavení a provedení dotazu tímto úryvkem a ponechte jej před polaczenie.close():

dotaz = "SELECT id, login FROM ucty WHERE login = ?"
vysledek = polaczenie.execute(dotaz, (hodnota,)).fetchall()
print("Výsledek:", vysledek)

Nyní získáte prázdný seznam: databáze hledá přihlašovací jméno, které doslova obsahuje celý předaný text. Když hodnotu hodnota změníte na "anna", dotaz vrátí pouze účet Anny. Čárka v (hodnota,) vytváří jednoprvkovou n-tici, kterou tento způsob předávání parametrů vyžaduje.

Nenahrazujte parametry ručním odstraňováním apostrofů ani formátováním textu, například pomocí f-stringu. Přihlašovací jméno s apostrofem může být platný údaj; aplikace jej musí umět bezpečně zpracovat. Syntaxe parametrů závisí na knihovně, proto nelze zápis ? bez ověření přenášet do každého ovladače.

Jaké následky může zranitelnost mít

SQL Injection může umožnit čtení cizích dat, obejití části kontrol přístupu, změnu záznamů nebo jejich smazání. Skutečný dopad závisí na dotazu, databázovém systému a oprávněních účtu aplikace. Samotné odhalení zranitelnosti automaticky neznamená ovládnutí celého serveru.

Ani nepřítomnost viditelné chyby nedokazuje bezpečnost. Aplikace může skrývat databázové zprávy a změněné chování se může projevit jen rozdílem v odpovědích. Naopak jediná chyba po zadání apostrofu je podnětem k analýze, nikoli sama o sobě důkazem zranitelnosti SQL Injection.

Co zkontrolovat ve vlastní aplikaci

Kontrolu začněte na místech, kde vznikají dotazy SQL:

Pro začátek vyberte jedno vyhledávání, které používá uživatelská data. Přidejte test s běžnou hodnotou i s textem obsahujícím apostrof a ověřte, že oba vstupy zůstávají daty a nemění strukturu dotazu.

Přečtěte si také

Zjistěte, jak PHP-FPM zpracovává požadavky PHP, čím se liší od webového serveru a jak nastavit procesy podle provozu a zdrojů hostingu.
Poznejte BIND, otevřený software pro server DNS: jak spravuje domény, jaké role plní a kdy se vyplatí provozovat vlastní server.
Zjistěte, k čemu slouží polský registr a číslo REGON, jak se liší od NIP a KRS a jak v oficiálním registru ověřit údaje o firmě.