SQL injection ( anglicky SQL injection / SQLi ) je jedním z nejběžnějších způsobů hackování stránek a programů , které pracují s databázemi , na základě vložení libovolného kódu SQL do dotazu .
SQL injection, v závislosti na typu použitého DBMS a podmínkách vkládání, může útočníkovi umožnit provést libovolný dotaz do databáze ( například číst obsah libovolných tabulek , mazat, upravovat nebo přidávat data ), získat možnost číst a/nebo zapisovat místní soubory a provádět libovolné příkazy na napadeném serveru.
Útok typu SQL injection může být možný kvůli nesprávnému zpracování vstupních dat používaných v dotazech SQL.
Vývojář databázových aplikací by si měl být vědom takovýchto zranitelností a podniknout kroky, aby zabránil vkládání SQL.
Existují tři hlavní třídy útoků založených na SQL injection:
Řekněme, že serverový software , který obdrží vstupní parametr id, jej použije k vytvoření dotazu SQL. Zvažte následující skript PHP :
$id = $_REQUEST [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = " . $id );Pokud je serveru předán parametr id rovný 5 (například: http://example.org/script.php?id=5 ), provede se následující SQL dotaz:
SELECT * FROM news WHERE id_news = 5Pokud však útočník předá řetězec -1 OR 1=1 jako parametr id (například takto: http://example.org/script.php?id=-1+OR+1=1 ), pak požadavek bude proveden:
SELECT * FROM news WHERE id_news = - 1 NEBO 1 = 1Změna vstupních parametrů přidáním konstruktů jazyka SQL k nim tedy způsobí změnu v logice provádění SQL dotazu (v tomto příkladu se místo novinek s daným identifikátorem vyberou všechny novinky v databázi, protože výraz 1=1 je vždy pravda - výpočty se provádějí pomocí nejkratšího obrysu v diagramu ).
Předpokládejme, že serverový software, který obdržel požadavek na vyhledávání dat ve zprávách s parametrem search_text, jej použije v následujícím dotazu SQL (zde jsou parametry uvozeny):
$search_text = $_REQUEST [ 'hledaný_text' ]; $res = mysqli_query ( "SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('% $search_text %')" );Vytvořením dotazu jako http://example.org/script.php?search_text=Test získáme následující SQL dotaz, který se má provést:
SELECT id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( '%Test%' )Ale vložením znaku citace (který se používá v dotazu) do parametru search_text, můžeme drasticky změnit chování SQL dotazu. Například předáním hodnoty ' )+a+(news_id_author='1 ) jako parametru search_text zavoláme dotaz, který se má provést:
SELECT id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( ' %' ) a ( news_id_author = '1 %' )Jazyk SQL umožňuje kombinovat výsledky více dotazů pomocí operátoru UNION . To poskytuje útočníkovi příležitost získat neoprávněný přístup k datům.
Uvažujme skript zobrazení zpráv ( identifikátor zprávy, která se má zobrazit, je předán v parametru id ):
$res = mysqli_query ( "SELECT id_news, záhlaví, tělo, autor FROM news WHERE id_news = " . $_REQUEST [ 'id' ]);Pokud útočník předá -1 UNION SELECT 4 uživatelské jméno, heslo,1 FROM admin jako parametr id , způsobí to provedení SQL dotazu.
SELECT id_news , hlavička , tělo , autor FROM novinky WHERE id_news = - 1 UNION SELECT 1 , uživatelské jméno , heslo , 1 FROM adminVzhledem k tomu, že zprávy s identifikátorem -1 určitě neexistují, nebudou z tabulky zpráv vybrány žádné záznamy, ale výsledek bude obsahovat záznamy, které byly v důsledku SQL injection neoprávněně vybrány z tabulky admin.
V některých případech může hacker zaútočit, ale nevidí více než jeden sloupec. V případě MySQL může útočník použít funkci:
group_concat ( col , symbol , col )který spojuje několik sloupců do jednoho. Například pro výše uvedený příklad by volání funkce bylo:
- 1 UNION SELECT group_concat ( uživatelské jméno , 0 x3a , heslo ) FROM adminDotaz SQL ovlivněný touto chybou zabezpečení má často strukturu, která ztěžuje nebo znemožňuje použití sjednocení. Například skript:
$res = mysqli_query ( "VYBRAT autora Z news WHERE id=" . $_REQUEST [ 'id' ] . " A LIKE autorovi ('a%')" );zobrazuje jméno autora zprávy podle předaného identifikátoru id pouze v případě, že jméno začíná písmenem a a vkládání kódu pomocí operátoru UNION je obtížné.
V takových případech útočníci používají metodu escapování části požadavku pomocí znaků komentáře ( /* nebo -- v závislosti na typu DBMS).
V tomto příkladu může útočník předat skriptu parametr id s hodnotou -1 UNION SELECT heslo FROM admin/* , čímž spustí dotaz
VYBRAT autora Z novinek WHERE id =- 1 UNION SELECT heslo FROM admin /* A LIKE autorovi ('a%')ve které je část dotazu ( AND autorovi LIKE ('a%') ) označena jako komentář a nemá vliv na provedení.
Symbol ; se používá k oddělení příkazů v jazyce SQL ; ( středník ) vložením tohoto znaku do dotazu je útočník schopen provést více příkazů v jednom dotazu, avšak ne všechny dialekty SQL tuto schopnost podporují.
Například pokud v parametrech skriptu
$id = $_REQUEST [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = $id " );útočník předá konstrukci obsahující středník, například 12;INSERT INTO admin (uživatelské jméno, heslo) VALUES ('HaCkEr', 'foo'); pak budou provedeny 2 příkazy v jednom dotazu
SELECT * FROM novinky WHERE id_news = 12 ; INSERT INTO admin ( uživatelské jméno , heslo ) VALUES ( 'HaCkEr' , 'foo' );a do tabulky admin bude přidán neautorizovaný záznam HaCkEr.
V této fázi útočník zkoumá chování serverových skriptů při manipulaci se vstupními parametry, aby odhalil jejich anomální chování. Manipulace probíhá se všemi možnými parametry:
Manipulace zpravidla spočívá v nahrazení jednoduchých (zřídka dvojitých nebo zpětných) uvozovek do parametrů znaků.
Neobvyklé chování je jakékoli chování, při kterém se stránky načtené před a po nahrazení nabídky liší (a nezobrazují stránku formátu neplatného parametru).
Nejběžnější příklady anomálního chování jsou:
atd. Je třeba mít na paměti, že existují případy, kdy chybové zprávy kvůli specifikům označení stránky nejsou v prohlížeči viditelné, ačkoli jsou přítomny v jeho HTML kódu.
Design | Komentář ke zbytku řádku | Získat verzi | Zřetězení řetězců |
---|---|---|---|
MySQL | -- ..., /* ..., nebo# ... | version() | concat (string1, string2) |
MS SQL | -- ... | @@version | string1 + string2 |
Věštec | -- ...nebo/* ... | select banner from v$version |
string1 || string2 neboconcat (string1, string2) |
MS Access | Vložení bajtu NULL do požadavku:%00... | ||
PostgreSQL | -- ... | SELECT version() | string1 || string2,CONCAT('a','b') |
Sybase | -- ... | @@version | string1 + string2 |
IBM DB2 | -- ... | select versionnumber from sysibm.sysversions | string1 || string2nebostring1 concat string2 |
Ingres | -- ... | dbmsinfo('_version') | string1 || string2 |
Pro ochranu před tímto typem útoku je nutné pečlivě filtrovat vstupní parametry, jejichž hodnoty budou použity k sestavení SQL dotazu.
Předpokládejme, že kód, který generuje požadavek (v programovacím jazyce Pascal ), vypadá takto:
statement := 'SELECT * FROM users WHERE name = "' + userName + '";' ;Chcete-li provést vkládání kódu (uzavření řetězce začínajícího uvozovkou jinou uvozovkou před ukončením aktuální závěrečnou uvozovkou, aby se dotaz rozdělil na dvě části), bylo nemožné, pro některé DBMS , včetně MySQL , je nutné uvádět všechny parametry řetězce . . V samotném parametru nahraďte uvozovky za \, apostrof za \', zpětné lomítko za \\ (toto se nazývá „ escapování speciálních znaků “). To lze provést pomocí následujícího kódu:
statement := 'SELECT * FROM users WHERE name = ' + QuoteParam ( userName ) + ';' ; function QuoteParam ( s : string ) : string ; { na vstupu - řetězec; výstupem je řetězec v uvozovkách se speciálními znaky nahrazenými } var i : integer ; cíl : řetězec _ begin Dest := '"' ; for i := 1 to length ( s ) do case s [ i ] of ' '' ' : Dest := Dest + '\ '' ' ; '"' : Dest := Dest + '\"' ; '\' : Dest := Dest + '\\' ; else Dest := Dest + s [ i ] ; end ; QuoteParam := Dest + '"' ; konec ;Pro PHP může být filtrování takto:
$query = "SELECT * FROM users WHERE user='" . mysqli_real_escape_string ( $user ) . "';" ;Vezměme si další žádost:
prohlášení := 'SELECT * FROM users WHERE id = ' + id + ';' ;V tomto případě má pole idčíselný typ a nejčastěji není v uvozovkách. Proto "uvozování" a nahrazování speciálních znaků sekvencemi escape nefunguje. V tomto případě pomáhá kontrola typu; pokud proměnná idnení číslo, dotaz by se neměl spustit vůbec.
Například v Delphi pomáhá těmto injekcím čelit následující kód:
if TryStrToInt ( id , id_int ) then příkaz := Formát ( 'SELECT * FROM users WHERE id =%0:d;' , [ id_int ]) ;Pro PHP by tato metoda vypadala takto:
$query = 'SELECT * FROM users WHERE id = ' . ( int ) $id ;Chcete-li provést změny v logice provádění dotazu SQL, je vyžadováno vložení dostatečně dlouhých řetězců. Minimální délka vloženého řetězce ve výše uvedených příkladech je tedy 8 znaků („ 1 OR 1=1 “). Pokud je maximální délka platné hodnoty parametru malá, pak jednou z metod ochrany může být maximální zkrácení hodnot vstupních parametrů.
Pokud je například známo, že pole idve výše uvedených příkladech může nabývat hodnot nejvýše 9999, můžete „odříznout další“ znaky a ponechat ne více než čtyři:
statement := 'SELECT * FROM users WHERE id = ' + LeftStr ( id , 4 ) + ';' ;Mnoho databázových serverů podporuje možnost posílat parametrizované dotazy (připravené příkazy). V tomto případě jsou parametry externího původu odeslány na server odděleně od samotného požadavku nebo jsou automaticky escapovány klientskou knihovnou. K tomu se používají
Například
var sql , param : řetězec begin sql := 'vyber :text jako hodnotu z dual' ; param := 'alfa' ; Dotaz1 . sql . Text : = sql Dotaz1 . ParamByName ( 'text' ) . AsString := param ; Dotaz1 . otevřít ; ShowMessage ( Query1 [ 'hodnota' ]) ; konec ;