SQL Injection

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 19. prosince 2021; kontroly vyžadují 9 úprav .

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.

Typy útoků, jako je SQL injection

Existují tři hlavní třídy útoků založených na SQL injection:

Princip SQL Injection Attack

Ř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 = 5

Pokud 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 = 1

Změ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 ).

Vložení do parametrů řetězce

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 %' )

Pomocí UNION

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 admin

Vzhledem 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.

Pomocí UNION + group_concat()

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 admin

Query tail escaping

Dotaz 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í.

Rozdělení SQL dotazu

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.

SQL Injection Attack Techniques

Hledání skriptů zranitelných vůči útoku

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:

  • Data předaná metodami POST a GET
  • hodnoty [HTTP Cookie]
  • HTTP_REFERER (pro skripty)
  • AUTH_USER a AUTH_PASSWORD (při použití ověřování)

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:

  • zobrazují se různé chybové zprávy;
  • při požadavku na data (například novinky nebo seznam produktů) se požadovaná data vůbec nezobrazují, přestože je stránka zobrazena

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

Ochrana proti útokům, jako je SQL injection

Pro ochranu před tímto typem útoku je nutné pečlivě filtrovat vstupní parametry, jejichž hodnoty budou použity k sestavení SQL dotazu.

Parametry filtrovacího řetězce

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 ) . "';" ;

Filtrování celočíselných parametrů

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 ;

Zkrácení vstupních parametrů

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 ) + ';' ;

Použití parametrizovaných dotazů

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í

  • v Delphi  - vlastnost TQuery.Params;

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 ;
  • v PerluDBI::quote nebo DBI::prepare;  _
  • v Javě  prostřednictvím třídy PreparedStatement;
  • v C#  - vlastnost SqlCommand.Parameters;
  • v PHP  - MySQLi (při práci s MySQL ), PDO.

Viz také

Odkazy