Co je SQL Injection a jak se mu bránit
Autor: Redakce Domeny.ForSale 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:
- U všech hodnot pocházejících zvenčí nahraďte spojování textu parametry.
- Zkontrolujte přímo psané dotazy i tehdy, když používáte ORM, tedy vrstvu mapující objekty aplikace na data v databázi.
- Názvy sloupců a směr řazení vybírejte z uzavřeného seznamu povolených možností. Parametry pro hodnoty obvykle takové prvky syntaxe nahradit nemohou.
- Omezte oprávnění databázového účtu na operace, které aplikace potřebuje.
- Nezobrazujte uživatelům podrobné databázové chyby ani úplné dotazy obsahující důvěrná data.
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.
