PHP – 35. díl – SQL příkazy a bezpečnost

35. díl seriálu o PHP bude věnován bezpečnosti při uživatelských vstupech do SQL příkazů.

Úvod

Pokud do SQL příkazů dáváte hodnoty, které zadal uživatel, máte potencionální bezpečnostní problém. Jedna ze zásad, která by při psaní programů měla platit je nikdy nevěřit ničemu, co zadal uživatel. Pokud totiž poučený a zkušený uživatel sedne k takovému programu, může pozměnit váš SQL příkaz tak, aby dělal něco jiného, než jste původně chtěli. A to by se vám opravdu nikdy nemělo stát.

Představte si třeba, že byste měli takový SQL příkaz:

$sql = "UPDATE user SET nick = `{$_GET[`nick`]}` WHERE user_id=10";

Jak je vidět, do SQL dotazu vstupuje hodnota z pole $_GET, což je hodnota vstupního pole parametru předaného pomocí metody GET. Uvnitř výrazu $_GET[‘nick’] se tedy může skrývat opravdu cokoli a je zde skryta bezpečnostní díra pro řádění chytrého hackera. Ten pozmění vstup tak, že parametr nick bude vypadat takto:

nick=sandokan’,credit=’100000

a rázem bude výsledný SQL dotaz vypadat nějak takto:

$sql = "UPDATE user SET nick = `sandokan`,credit=`100000` WHERE user_id=10";

A chytrý hacker dosáhl toho, že kromě nastavení přezdívky (anglicky nick) si nastavil i kredit na 100 000 bodů. Vy jste samozřejmě vůbec nepředpokládali, že někdo něco podobného s vaším kódem vůbec udělá.

Kromě tohoto příkladu může hacker způsobit spoustu dalších, i velmi destruktivních akcí ve vaší databázi, pokud mu takto nahrajete, a nebudete speciálně ošetřovat uživatelské vstupy, které používáte ve svých SQL příkazech.

Musím říci, že se na mě obrací spoustu lidí ohledně rady PHP, a když mi ukazují svoje PHP skripty, tak zjišťuji, že téměř všichni bohužel mají ve svých programech bezpečnostní díry tohoto typu.

Dále si ukážeme, jak můžeme nebezpečí tohoto typu eliminovat a zamezit tak těmto bezpečnostním dírám.

Funkce mysql_escape_string

Funkce mysql_escape_string slouží k tomu, aby všechny znaky, které by mohly mít výše uvedené bezpečnostní potíže byly opatřeny zpětným lomítkem. Toto opatření zabrání tomu, aby upravený vstup mohl způsobit nějakou škodu, nebo vedlejší efekt, který původně programátor PHP skriptů nezamýšlel.

Funkce mysql_escape_string nahrazuje několik kontroverzních znaků, jako například znak nového řádku nahradí dvojicí znaků \n, znak zpětného lomítka nahradí dvojicí zpětných lomítek \\, znak apostrofu nahradí dvojicí znaků \‘, apod..

Jak by tedy při použití funkce mysql_escape_string měl vypadat náš úvodní SQL příkaz, aby zlý hacker odešel s nepořízenou? Nějak takto:

$sql = "UPDATE user SET nick = `".mysql_escape_string($_GET[`nick`])."` WHERE user_id=10";

Na příkladu je vidět, jak by to mělo být správně zařízeno: každý vstup, který je získáván od uživatele by měl být uzavřen do funkce mysql_escape_string, nebo podobné s podobnou funkcí.

Funkce mysql_escape_string je zařízena právě pro použití uvnitř SQL příkazů pro MySQL. Přesněji řečeno, funkce mysql_escape_string se smí použít všude, kde jsme uvnitř apostrofů v SQL příkazu. Samotná MySQL rozumí upraveným znakům ze zpětným lomítkem, které produkuje tato funkce.

Funkce mysql_real_escape_string

Druhou možností, jak přeměnit nebezpečné znaky na bezpečné je použití funkce mysql_real_escape_string. Na rozdíl od předcházející funkce mysql_escape_string bere tato funkce v úvahu i nastavení aktuální znakové sady spojení. Z tohoto důvodu má také funkce mysql_real_escape_string o jeden parametr navíc, a to identifikátor spojení k databázi:

mysql_real_escape_string (řetězec, spojení_k_databázi)

Funkce mysql_real_escape_string vám nebude pracovat všude. Tato funkce je poměrně mladá a byla přidána do PHP poměrně nedávno. Pokud jí použijete v PHP verze starší, než 4.3.0, nebude k dispozici a nebude vám správně pracovat. Proto používejte funkci mysql_real_escape_string jen v případě, kdy jste si naprosto jisti, že vaše PHP skripty budou pracovat na novějších verzích PHP. Proto zatím asi dávejte přednost funkci mysql_escape_string.

Může se vám tedy stát, že když budete zkoušet pracovat s funkcí mysql_real_escape_string, že se vám zobrazí podobné hlášení jako je toto:

Fatal error: Call to undefined function: mysql_real_escape_string() in c:\inet_srv\http\doc_root\xxx.php on line 12

Pokud obdržíte podobné hlášení, znamená to, že pracujete pod PHP starší verze, než je 4.3.0 a tudíž nemáte přístup k funkci mysql_real_escape_string. Pak namísto ní použijte funkci mysql_escape_string.

Závěr

Nevěřte tedy nikdy ničemu, co přichází od uživatele, a pokud chcete hodnotu od uživatele použít v SQL příkazu, nezapomeňte nechat takový vstup projít nejdříve funkcí mysql_escape_string, nebo novější funkcí mysql_real_escape_string.

Diskuze (21) Další článek: Chyba v Adobe Acrobatu může zpřístupnit citlivé informace

Témata článku: , , , , , , , , , , , , , , , ,