SQL injection
Úvod
SQL injection je bezpečnostná chyba založená na možnosti manipulovať s datami v databáze bez nutnosti mania legitímneho prístupu. Bezpečnostná chyba sa netýka iba webových technologií, ale všetkých aplikácií pracujúcich s databázami. Zneužitie môže viesť k získaniu citlivých údajov, ako napr. prihlasovacie údaje, osobné údaje (čísla bankových účtov, rodné čísla...) a v niektorých prípadoch može viesť aj k vykonaniu systémového príkazu, prípadne k ovládnutiu celého serveru. Princípom je vkladanie nových SQL dotazov do už existujúcich dotazov.[1]
Popis jazyka SQL
SQL je skratka pre Structured Query Language, teda štrukturovaný jazyk používaný v databázach pre prácu s datami. SQL príkazy sú používané pre vykonanie príkazov, ktoré menia databázu. Môžu napr. aktualizovať, získavať alebo pridávať data do databázy. Medzi rôzne databázové systémy patria: Oracle, Sybase, Microsoft SQL Server, Access, Ingres atď. Väčšina SQL príkazov sa skladá zo štandardných príkazov "Select", "Insert", "Update", "Delete", "Create", a "Drop", ktoré môžu byť použité na každom z vyššie popísaných systémov.[2]
Zneužitie prihlasovacieho formulára
Prihlasovacie formuláre väčšinou využívajú databázu pre overenie alebo pridanie odosielaných dát. Klasický príklad na príkaz ktorý pri prihlasovaní overí či je daný užívateľ v databáze by mohol vyzerať v php napr. takto:
SELECT * FROM uzivatelia WHERE meno = '$zadaneMeno' AND heslo='$zadaneHeslo';
Pri vložení do zadaneMeno apostrofu ' vznikne SQL príkaz ktorý skončí chybou. Pokiaľ však je vložený do zadaneMeno SQL komentár spolu s apostrofom a účtom za ktorý chce byť útočník prihlásený ("admin'--") vznikne príkaz, ktorý neoveruje správnosť zadaného hesla a útočník sa môže týmto spôsobom napr. prihlásiť do systemu bez toho, že by vedel heslo.
SELECT * FROM uzivatelia WHERE meno = 'admin'--' AND heslo='';
Podobný výsledok sa dá dosiahnuť použitím operátorov OR a AND zadaním za heslo "' OR 1=1--":
SELECT * FROM uzivatelia WHERE meno = '$zadaneMeno' AND heslo='' OR 1=1--';
Keďže 1=1 je pravda vždy tak môže útočník zadať akékoľvek heslo a vždy bude prihlásený do systému.
Ochrana na strane aplikácie
[3] Priamočiary prístup ako zabrániť SQL je takzvané "Escapovanie" znakov, ktoré majú špeciálny význam v SQL. Napríklad každý výskyt apostrofu (') môže byť nahradený dvoma úvodzovkami pre vytvorenie validného reťazca. Napr. v php sa pre takéto escapovanie používa funkcia mysql_real_escape_string() ešte pred odoslaním dotazu do databázy.
Příklad v jazyku Perl
$query = $sql->prepare("SELECT * FROM uzivatelia WHERE meno = ". $sql->quote($zadaneMeno));
Príklad v jazyku PHP a MySQLi
$mysqli = @mysqli_connect(db_hostname, db_username, db_password, db_name); //otvorenie nového spojenia do MySQL
$val1 = mysqli_real_escape_string($mysqli, $_POST["va1"]); //escapuje nepovolené znaky zo superglobálnej premennej
$val2 = mysqli_real_escape_string($mysqli, $_GET["va1"]); //escapuje nepovolené znaky zo superglobálnej premennej
$query = sprintf("SELECT * FROM `uzivatelia` WHERE value1='%s' AND value2='%s'", $val1, $val2); //vytvorí dotaz s už overenými hodnotami
$result = mysqli_query($mysqli, $query); //vracia výsledok dotazu
Takto môže vyzerať ošetrený kód proti sql injection útoku. Vstupné premenné sú ošetrené pomocou funkcie mysqli_real_escape_string(mysqli $mysqli, string $escapestr), ktorá pridá spätné lomítko znakom \x00, \r, \n, \, ', , a \x1a. Táto funkcia by mala byť použitá pri každom dotaze do databázy, avšak občas je zbytočná - napr. pri premennej ktorá ma dátový typ (int).
Príklad v jazyku PHP a Oracle
$stmt = oci_parse($connOci, 'SELECT * FROM LOGIN WHERE jmeno = :login');
oci_bind_by_name($stmt, ':login', $_POST['login']);
oci_execute($stmt);
Existuje veľa ďalších rôznych funkcií v PHP pre ochranu proti SQLi špecifických pre rôzne databázy, napr. pg_escape_string() pre PostgreSQL.
Pozri aj
Externé odkazy
http://www.sqlcourse.com/intro.html (po anglicky)
http://www.pcmag.com/article2/0,2817,2421524,00.asp (po anglicky)
http://www.w3schools.com/sql/sql_injection.asp (po anglicky)
http://www.unixwiz.net/techtips/sql-injection.html (po anglicky)