11) Používejte pro předávání parametrů databázi prepared statements, která jsou pro to určená a kromě vyššího výkonu také zamezí drtivé většině SQL injection.
Jenže to by PHP frameworky museli programovat lidé, kteří o databázích něco vědí a nemají nezměrnou touhu stále znovu a znovu vynalézat šišaté kolo.
Vlákno názorů k článku
Děravé databáze: věčná láska hackerů
Flasi (neregistrovaný)
---.hq.iol.cz
5. 1. 2010 9:08
Re: 11)
Nebo to rovnou pište v prostředích, kde při práci s databází patří používání typově bezpečných parametrů ke slušnému vychování - jako jsou např. .NET nebo Java.
A pro zasmání:
http://xkcd.com/327/
A pro zasmání:
http://xkcd.com/327/
Flasi (neregistrovaný)
---.ct.cz
8. 1. 2010 10:42
Re: 11)
Nepíši, že SQL injection nemůže postihnout aplikaci napsanou v Javě, nebo .NETu.
Píši, že používání parametrů u SQL příkazů je v těchto prostředích "součást slušného vychování". Tedy, že v těchto přostředích se k eliminaci rizika SQL injekce stačí chovat podle elemetárních tutoriálů. Pochopitelně, když někdo SQL injekci hrozně moc chce, tak mu v tom Java ani .NET bránit nebudou a poskládat SQL dotaz ze stringů ze vstupních polí ho nechají.
Píši, že používání parametrů u SQL příkazů je v těchto prostředích "součást slušného vychování". Tedy, že v těchto přostředích se k eliminaci rizika SQL injekce stačí chovat podle elemetárních tutoriálů. Pochopitelně, když někdo SQL injekci hrozně moc chce, tak mu v tom Java ani .NET bránit nebudou a poskládat SQL dotaz ze stringů ze vstupních polí ho nechají.
Pavel Stehule (neregistrovaný)
---.nic.cz
5. 1. 2010 9:43
Re: 11)
No, a pak se lidé diví, že SQL injection je tak časté. Měl jsem dodat, SQL je ochranou proti SQL injection na správně použitém SQL příkazu. Dynamický ORDER BY je něco, co bych si nikdy nedovolil napsat, a také to nikomu nedoporučuji.
Pokud chcete bezpečně řešit takový dotaz, pak Vám nezbývá než SQL příkaz namnožit:
if col = ... THEN
SELECT FROM ORDER BY 1;
else
SELECT FROM ORDER BY 2;
atd
Pokud chcete bezpečně řešit takový dotaz, pak Vám nezbývá než SQL příkaz namnožit:
if col = ... THEN
SELECT FROM ORDER BY 1;
else
SELECT FROM ORDER BY 2;
atd
5. 1. 2010 11:34
Re: 11)
Haha, jedno řešení lepší než druhé
Problém je v tom, že dnes dělá programátora každý jouda bez vzdělání.
Problém je v tom, že dnes dělá programátora každý jouda bez vzdělání.
5. 1. 2010 13:17
Re: 11)
Přesně tak. U řešení Pavla Stěhuleho si mohu být jistý, že mi tam nevleze dotaz, který by položil databázový server. To mi určitě stojí za to, že napíšu o pár řádek víc.
5. 1. 2010 15:00
Re: 11)
Vy ale nepíšete jen o pár řádek víc. Vy kopíruju celý dotaz. Předem vím jak to dopadne. Až ho budete měnit, na jeden z výskytů zcela jistě zapomenete.
Takže prosím běžně nad svými programátorskými znalostmi onanovat na jakpsatweb :)
Takže prosím běžně nad svými programátorskými znalostmi onanovat na jakpsatweb :)
Pavel Stehule (neregistrovaný)
---.nic.cz
5. 1. 2010 15:34
Re: 11)
Od toho je testování. Ať už unit testy nebo regresní testy.
Pokud se vyhnu dynamickému SQL, tak poměrně snadno mohu otestovat syntaktickou správnost všech SQL dotazů, které se vyskytují v aplikaci. Dynamické SQL není testovatelné.
Samozřejmě, že tu proti sobě jdou dvě strategie - úspora kódu X efektivitě a bezpečnosti. Souhlasím, můžete udělat chybu. Na druhou stranu - dynamické SQL Vás před chybami neochrání - testovat musíte tak jako tak - a navíc riskujete děravost aplikace.
Jedna věc je, když píšete lokální z internetu nedostupné aplikace - riziko SQL injektáže není až tak velké. Jen riskujete, že Vám uživatelé vygenerují pomalý dotaz, což patrně přežijete. Psát dobré internetové aplikace ovšem vyžaduje docela dost znalostí - pohybujete se v mnohem rizikovějším prostředí a přetížit SQL server náporem uživatelů je mnohem menší problém - tudíž web s trochou větší návštěvností je mnohem lépe optimalizován než typické vnitropodnikové aplikace.
Pokud se vyhnu dynamickému SQL, tak poměrně snadno mohu otestovat syntaktickou správnost všech SQL dotazů, které se vyskytují v aplikaci. Dynamické SQL není testovatelné.
Samozřejmě, že tu proti sobě jdou dvě strategie - úspora kódu X efektivitě a bezpečnosti. Souhlasím, můžete udělat chybu. Na druhou stranu - dynamické SQL Vás před chybami neochrání - testovat musíte tak jako tak - a navíc riskujete děravost aplikace.
Jedna věc je, když píšete lokální z internetu nedostupné aplikace - riziko SQL injektáže není až tak velké. Jen riskujete, že Vám uživatelé vygenerují pomalý dotaz, což patrně přežijete. Psát dobré internetové aplikace ovšem vyžaduje docela dost znalostí - pohybujete se v mnohem rizikovějším prostředí a přetížit SQL server náporem uživatelů je mnohem menší problém - tudíž web s trochou větší návštěvností je mnohem lépe optimalizován než typické vnitropodnikové aplikace.
5. 1. 2010 16:05
Re: 11)
Pomíjíte, že téměř každá SQL má detailní možnosti nastavení práv, takže každá databáze může mít jednoho db uživatele pro web (pouze prohlížení), jednoho pro administraci (zápis) a dalšího pro databázové příkazy (třeba zrovna ten drop tabulky)
Jenže který hosting by tohle uměl a který programátor by to používal?
Jenže který hosting by tohle uměl a který programátor by to používal?
5. 1. 2010 16:10
Re: 11)
Třeba vlastní databázový server? :)
Různé urovně práv nevyřeší potenciální přetížení databázového serveru.
Různé urovně práv nevyřeší potenciální přetížení databázového serveru.
Pavel Stehule (neregistrovaný)
---.nic.cz
5. 1. 2010 16:17
Re: 11)
To nepomíjím. Pomocí práv lze minimalizovat škody způsobené SQL injektáží - nicméně nastavením práv se rizika SQL injektáže nezbavíte - pokud nepřistoupíte k dost razantní strategii a neobalíte všechny SQL příkazy uloženou procedurou, která běží v security definer modu - čímž byste běžného uživatele odřízl.
Nastavení práv v SQL databázi lze pouze minimalizovat dopady. Ale již jen to, že se Vám pomocí SQL injektáže útočník dostane k uživatelským datům, je problém, a tomu se nastavením práv nevyhnete. Všimněte si - většina problémů způsobených SQL injektáží není o tom, že by někdo pozměnil strukturu, ale o tom, že někdo získal data, která získat neměl.
Nastavení práv v SQL databázi lze pouze minimalizovat dopady. Ale již jen to, že se Vám pomocí SQL injektáže útočník dostane k uživatelským datům, je problém, a tomu se nastavením práv nevyhnete. Všimněte si - většina problémů způsobených SQL injektáží není o tom, že by někdo pozměnil strukturu, ale o tom, že někdo získal data, která získat neměl.
5. 1. 2010 16:08
Re: 11)
Pokud jsou dotazy u sebe, jako že v příkladu byly, tak si troufám tvrdit, že se na 90% nepřehlédnu. Zbytek snad odhalí testování. Pokud dovolím sestavit SQL dynamicky, neotestuji pravděpodobně všechny možnosti, které mi od uživatele mohou přijít, což je potenciální díra v aplikaci.
Osobně raději vezmu duplicitu kódu než kód, který do databáze pustí něco neočekávaného.
Netvrdím, že bych kopíroval celý dotaz. Pravděpodobně bych ho rozdělil na několik částí. Zde ale už porušuji čitelnost a trochu i bezpečnost, protože nemohu scannováním zdrojáku otestovat syntaktickou správnost všech dotazů.
Pokud máme v debatě pokračovat dál, rád bych slyšel odpověď na Pavlovu otázku s ohledem na 3 zmíněná kritéria.
Osobně raději vezmu duplicitu kódu než kód, který do databáze pustí něco neočekávaného.
Netvrdím, že bych kopíroval celý dotaz. Pravděpodobně bych ho rozdělil na několik částí. Zde ale už porušuji čitelnost a trochu i bezpečnost, protože nemohu scannováním zdrojáku otestovat syntaktickou správnost všech dotazů.
Pokud máme v debatě pokračovat dál, rád bych slyšel odpověď na Pavlovu otázku s ohledem na 3 zmíněná kritéria.
Filip Jirsák (neregistrovaný)
---.oksystem.cz
5. 1. 2010 16:19
Re: 11)
Vy ale nepíšete jen o pár řádek víc. Vy kopíruju celý dotaz. Předem vím jak to dopadne. Až ho budete měnit, na jeden z výskytů zcela jistě zapomenete.To je jenom věc toho, jak to napíšete – a do komentáře se to asi napíše v této formě, protože je to nejsrozumitelnější. jinak se to dá samozřejmě napsat jako šablona, kam doplníte vlastní parametr (tedy ne zadaný uživatelem), nebo to můžete mít jako uloženou proceduru na serveru a té předáte jako parametr jenom hodnotu z výčtového typu. Pořád je to tisíckrát lepší než nechat uživatele psát si vlastní SQL příkazy.
uživatel si přál zůstat v anonymitě
---.adsl.dial-up.cz
11. 1. 2010 9:42
Re: 11)
sql_query = ...dotaz bez ORDER...
if OrderParameterIsValid( $user_order_input ) then sql_query = sql_query + order by $user_order_input
Jak vypada IsValid myslim neni moc dulezite, v PHP to osobne resim tim ze mam array s validnimi hodnotami a pak staci udelat array_search nebo array_key_exists.
Neni zadny duplicitni kod a je to myslim obstojne citelne. (IMHO je to lip citelne nez vas spagetovy if if if if.. kod)
"chytat indexy" - to je snad vec DB enginu, aby si dotaz zoptimalizoval (kdyz se mu udelaji patricne indexy do tabulek)? (samozrejme v krajnim pripade jde udelat dalsi if ktery se postara o specialni pripad)
if OrderParameterIsValid( $user_order_input ) then sql_query = sql_query + order by $user_order_input
Jak vypada IsValid myslim neni moc dulezite, v PHP to osobne resim tim ze mam array s validnimi hodnotami a pak staci udelat array_search nebo array_key_exists.
Neni zadny duplicitni kod a je to myslim obstojne citelne. (IMHO je to lip citelne nez vas spagetovy if if if if.. kod)
"chytat indexy" - to je snad vec DB enginu, aby si dotaz zoptimalizoval (kdyz se mu udelaji patricne indexy do tabulek)? (samozrejme v krajnim pripade jde udelat dalsi if ktery se postara o specialni pripad)
uživatel si přál zůstat v anonymitě
---.41.broadband10.iol.cz
5. 1. 2010 18:19
Re: 11)
No v PHP k obraně můžete využít pole, kde $uzivatelem_urcene_pole je index do asociativního pole, kde je teprve uložen název pole. Například takto
$table = {'kod' => 'id', 'jmeno' => 'name'};
$sql = "SELECT * FROM tabulka ORDER BY {$table[$uzivatelem_urcene_pole]}".
Pokud $uzivatelem_vlozene_pole je něco jiného, vrati se asi null ...
$table = {'kod' => 'id', 'jmeno' => 'name'};
$sql = "SELECT * FROM tabulka ORDER BY {$table[$uzivatelem_urcene_pole]}".
Pokud $uzivatelem_vlozene_pole je něco jiného, vrati se asi null ...
uživatel si přál zůstat v anonymitě
---.41.broadband10.iol.cz
5. 1. 2010 18:36
Re: 11)
No a ta hvězdička taky není bezpečná, dá se nahradit takto.
"SELECT {implode(',',$table)} FROM table ORDER BY {$table[$uzivatelem_vlozene_pole]}"
a klauzuli s polem lze nahradit jednoducho funkcí, kde bude korektně ošetřena neexistence indexu do pole.
"SELECT {implode(',',$table)} FROM table ORDER BY {$table[$uzivatelem_vlozene_pole]}"
a klauzuli s polem lze nahradit jednoducho funkcí, kde bude korektně ošetřena neexistence indexu do pole.
Pavel Stehule (neregistrovaný)
---.nic.cz
5. 1. 2010 9:49
Re: 11)
Až na malé výjimky nemá smysl uvažovat o Prepared Statement kvůli výkonu - ve většině případů je výkon stejný nebo může být i horší (zase tak často se SQL příkazy neopakují a optimalizace na dnešních strojích už neznamená takové zdržení). Ten soudobý smysl je v ochraně vůči SQL injection. Podobně se chovají tzv. Parametrized Queries - moderní databáze nabízejí obé - PQ mají výhody PP bez jejich nevýhod. Pokud používáte PQ, tak se musíte hodně snažit - v podstatě to nejde, abyste napsal SQL injection zranitelný dotaz. dalším argumentem pro PQ je čitelnost zápisu.
Ivan (neregistrovaný)
165.72.200.---
5. 1. 2010 16:22
Re: 11)
No minimalne na Oracle maji Prepared Statementy velky vyznam pro vykon.
1. vytvoreni exkucniho planu ma slozitost O(n!) kde n je pocet tabulek v joinu. Proto DB vygeneruje max. 80000 exekucnich planu a z nich zvoli nejlepsi.
2. Vytvoreni exekucniho planu vyzaduje exkluzivni zamek na nekterych sdilenych strukturach. Tim muzete zbytecne brzdit ostatni konexe. Vytvoreni exekucniho planu vyzaduje sdileny zamek jinych strukturach. To muze zbytecne zvysovat mnozstvi zprav mezi nody DB clusteru.
3. SQL prikazy se velice casto opakuji a na normalni DB se pomer mezi hard a soft parse pohybuje okolo 1:1000.
1. vytvoreni exkucniho planu ma slozitost O(n!) kde n je pocet tabulek v joinu. Proto DB vygeneruje max. 80000 exekucnich planu a z nich zvoli nejlepsi.
2. Vytvoreni exekucniho planu vyzaduje exkluzivni zamek na nekterych sdilenych strukturach. Tim muzete zbytecne brzdit ostatni konexe. Vytvoreni exekucniho planu vyzaduje sdileny zamek jinych strukturach. To muze zbytecne zvysovat mnozstvi zprav mezi nody DB clusteru.
3. SQL prikazy se velice casto opakuji a na normalni DB se pomer mezi hard a soft parse pohybuje okolo 1:1000.
Pavel Stehule (neregistrovaný)
---.nic.cz
5. 1. 2010 16:37
Re: 11)
Všechny kombinace se určitě nezkoušejí - viz http://redbook.cs.berkeley.edu/redbook3/lec7.html případně hledejte na googlu "dynamické programování".
Čím složitější SQL příkaz, tím méně by se Vám měl v db vyskytovat. Totéž - pokud se v db objevují opakující se SQL příkazy, tak to povětšinou znamená, že se někde udělala chyba - např. špatně konfigurované Hibernate. Konečně u prepared statement hrozí riziko neoptimálních prováděcích plánů z důvodů optimalizace na slepo.
Čím složitější SQL příkaz, tím méně by se Vám měl v db vyskytovat. Totéž - pokud se v db objevují opakující se SQL příkazy, tak to povětšinou znamená, že se někde udělala chyba - např. špatně konfigurované Hibernate. Konečně u prepared statement hrozí riziko neoptimálních prováděcích plánů z důvodů optimalizace na slepo.