Stripslahes, addslashes a magic_qotes_gpc - revisited
Není to tak dlouho,
co jsem tu psal o
obraně proti SQL injection v PHP a o užitečnosti funkcí zmíněných v nadpisu.
Celkem důkladně jsem přitom argumentoval ve prospěch řešení, kdy jsou všechny
vstupní proměnné skriptu protaženy přes funkci addslashes
(buď
ručně nebo automaticky) a to i za cenu toho, že se musí ve zbytku skriptu občas
stripslashnout, na což se často zapomíná a může to vést ke zkomoleným výstupům.
Tento názor už ale nezastávám. Posunul jsem se totiž ve svých úvahách trochu dál – a jako obvykle mým "posunovačem" nebyla žádná velká teorie, ale tisíce řádek napsaného kódu.
Většina lidí si dříve nebo později totiž napíše na zacházení s databází knihovnu – ať už je to jenom nějaký jednoduchý wrapper zastiňující rozdíly mezi dvěma verzemi databázoveho enginu, nebo nějaká komplexnější potvora. A tak mě napadlo: Proč do této knihovny nepřidat i schopnost escapování parametrů? Když budete k databázi přistupovat pouze přes tuto knihovnu, nestane se vám, že zapomenete na addslashnutí. A po programu se vám nebudou potulovat řetězce se zpětnými lomítky, jako v případě postupu naznačeného v mém starém článku na toto téma.
Pro jednoduchou ukázku toho, co mám na mysli, použiju analogii klasické
funkce sprintf
– říkejme jí třeba sql_sprintf
. Taková
funkce bude mít stejně jako obyčejný sprintf
jako první parametr
řetězec, ve kterém budou zástupné symboly %s
,
%d
apod., a za nimi bude seznam
hodnot, kterými se mají nahradit. Rozdíl bude v tom, že u %s
navíc
předaná hodnota projde přes addslashes
a vhodné bude i přidání
apostrofů okolo ní (aby se dal předat řetězcový parametr, který je NULL
).
Klasické volání databázového dotazu se změní z této podoby:
$result = mysql_query( "SELECT * FROM dogs WHERE name='" . $dogName . "' AND bitten_people < " . $n );
na následující:
$result = mysql_query(sql_sprintf( "SELECT * FROM dogs WHERE name=%s AND bitten_people < %d", $dogName, $n ));
A je po problémech.
Přiznávám, že jsem zatím žádnou obdobu funkce sql_sprintf
do
svých knihoven nezačlenil, a tak tak zůstává čirým myšlenkovým konstruktem
(můžete si ji zkusit implementovat za domácí úkol :-) Jediným důvodem pro to je,
že všechny projekty, na kterých teď pracuji, už jsou v příliš pokročilém stadiu,
abych v nich prováděl takové změny. Ale jakmile začnu tvořit něco nového, určitě
se naznačený princip někde v mém kódu objeví. A troufnu si vám doporučit totéž.