Ochrana proti SQL Injection v PHP

SQL injection je druh útoku, zpravidla na webové stránky, který se snaží přímo upravit obsah databáze, nebo alespoň se z ní snaží vypsat důležitá data. Takový útok spočívá ve vložení SQL kódu do nějakého nechráněného místa. Například mějme nechráněný SQL dotaz:

mysql_query("INSERT INTO table (column) VALUES ('" . $NechranenaPromenna . "')");

Pokud někdo místo vámi očekávaných dat vloží třeba do vašeho formuláře následující data

value'); DROP TABLE table;--

Bude výsledek SQL dotazu

mysql_query("INSERT INTO table (column) VALUES ('value'); DROP TABLE table;--')");

Dojde tedy k vytvoření nového SQL dotazu a jak jste asi vydedukovali, ke smazání tabulky table. Vidíte, že se nejedená o nic složitého. Takový útok zvládne i malé dítě. Otázka je, jak se proti tomu bránit.

Sice existuje několik způsobů ochrany proti SQL Injection, avšak snad jediná nejsprávnější je pomocí svazování proměnných. Běžné druhy ochran příkazy mysql_escape_string, mysql_real_escape_string jsou dnes již zastaralé a již brzy přestanou být funkční. Knihovnu MySQL totiž nahrazuje PDO, případně mysqli, které svazování proměnných zvládají velmi dobře. Svázání proměnných vám zaručí, že vkládaná data budou ochráněna tak jak je to potřeba. Pokud tedy budete toto využívat, nemusíte se SQL injection bát.

Svazování proměnných v PDO

Nejprve si řekněme co je to PDO. PDO je zkratka názvu PHP Data Objects, což je objektové rozhraní databází pro PHP, které umožňuje jednotným způsobem pracovat s rozličnými databázemi. Díky PDO, a s samozřejmě doinstalovanými příslušnými ovladači, můžete snadno pracovat s databázemi CUBRID, MS SQL Server, Firebird/Interbase, IBM, Informix, MySQL, MS SQL Server, Oracle, ODBC and DB2, PostgreSQL, SQLite a 4D. Přitom většina příkazů zůstává stejných, mění se jen příkazy specifické pro každou databázovou platformu.

Není na tom nic složitého. Hned si svazování (bind) ukážeme na příkladu.

$dbh = new PDO('mysql:host=localhost;dbname=lidicoznam;charset=utf8', $login, $heslo); //připojení k db a vybrání tabulky
$jmeno = $_POST['jmeno'];
$prijmeni = $_POST['prijmeni'];

$sth = $dbh->prepare('insert into uzivatele (jmeno, prijmeni) values (:jmeno, :prijmeni)');
$sth->bindValue(':jmeno', $jmeno, PDO::PARAM_STR);
$sth->bindValue(':prijmeni', $prijmeni, PDO::PARAM_STR);
$sth->execute(); //vykoná příkaz a vrátí počet ovlivněných řádků

Funkce prepare připraví SQL dotaz k vykonání. :jmeno a :prijmeni jsou jmenné parametry, které lze nahradit otazníky (viz. další příklad). Funkce bindValue svazuje proměnnou s parametrem. Konstanta DO::PARAM_STR říká, že se data mají interpretovat jako typ VAR, nebo VARCHAR. Seznam konstant naleznete v dokumentaci PHP.

Druhý způsob zápisu s otazníky

$jmeno = $_POST['jmeno'];
$prijmeni = $_POST['prijmeni'];
$sth = $dbh->prepare('insert into uzivatele (jmeno, prijmeni) values (?, ?)');
$sth->execute(array($jmeno, $prijmeni));

Jinak je velmi doporučeno vypínat emulaci svazování proměnných, která provádí parsování dotazu a hodnot před odesláním na server. Tím zcela zabráníte útočníkům provést útok.

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Nakonec je třeba uvést, že je při použití svazování proměnných dobré vypnout php direktivu magic_quotes_gpc. Jinak budete mít zbytečně moc zpětných lomítek v databázi.

Jedna myšlenka na “Ochrana proti SQL Injection v PHP”

  1. dikes, dobry clanok
    pochopil som tu funkciu „bindValue“
    z naglictiny mi to velmi neslo 🙂

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *