Invia.cz
Last minute
Tunisko
Dovolená v Chorvatsku
Pojeďte do Egypta
Bulharsko
Vydělávejte peníze s INVIA.CZ
SQL injection je technika napadení databázové vrstvy programu vsunutím (odtud „injection“) kódu přes neošetřený vstup a vykonání vlastního, samozřejmě pozměněného, SQL dotazu. Toto nechtěné chování vzniká při propojení aplikační vrstvy s databázovou vrstvou (téměř vždy se totiž jedná o dva různé programy) a zabraňuje se mu pomocí jednoduchého escapování potencionálně nebezpečných znaků.
Obsah |
V klasickém případě je útok na internetové stránky prováděn přes neošetřený formulář, manipulací s URL nebo třeba i podstrčením zákeřně upravené cookie. Bohužel, na internetu je stále velké množství webů, spravovaných převážně nezkušenými programátory, kteří o této technice útoku prostě neví a tuto kritickou chybu opomíjejí.
Mějme program odesílající dotaz do databáze:
statement := "SELECT * FROM uzivatele WHERE jmeno = '" + zadaneJmeno + "';"
Pokud však uživatel zadá jako jméno například:
a' or 'b'='b
aplikační program dotaz doplní a odešle databázi ve formě
statement := "SELECT * FROM uzivatele WHERE jmeno = 'a' or 'b'='b';"
což může zapříčinit přemostění autorizační procedury, protože 'b' = 'b' je vždy pravda.
Pro SQL injection se samozřejmě dají použít všechny dostupné příkazy, pokud bychom tedy v předešlém příkladě jako jméno zadali
a';DROP TABLE uzivatele; --
vypadal by dotaz při odeslání serveru jako
statement := "SELECT * FROM uzivatele WHERE jmeno = 'a';DROP TABLE uzivatele; --';"
čímž se nám povedlo smazat celou tabulku uživatelů. Poslední apostrof je pomocí sekvence – zapoznámkován a nemá žádý vliv.
Podobných průniků je samozřejmě celá řada, díky klauzulím UNION a JOIN nejsme ani vázáni na tabulku předepsanou v části FROM a můžeme vypisovat data odkudkoliv z databáze.
Nejjednodušší obrana spočívá ve vhodném escapování vstupu. Prakticky každý skriptovací program s podporou databáze má nějakou vestavěnou funkci pro escapování znaků před jejich použitím v dotazu. Například pro Perl stačí využít
$query = $sql->prepare( "SELECT * FROM uzivatele WHERE jmeno = " . $sql->quote($zadaneJmeno) );
pro PHP (v příkladu implementace MySQL):
$sql = "SELECT * FROM uzivatele WHERE jmeno = " . mysql_real_escape_string($zadaneJmeno); mysql_query($sql);
Pokud si navíc ještě více potrpíme na bezpečnost (může se stát, že na ošetření vstupu někde prostě zapomeneme), můžeme navíc vypnout vypisování chyb. Pokud by pak útočník na nějaký napadnutelný vstup narazil, nedozví se o tom z chybových hlášení.
V databázi můžeme útoku zabránit (nebo ho přinejmenším extrémně ztížit) vhodným nastavením práv uživatele, se kterými bude program přistupovat. Málokdy je třeba přímo z aplikační vrstvy mazat tabulky či dokonce databáze, proto stačí povolit jen základní SQL příkazy.