Programátorská sociální síť a materiálová základna pro C#, Java, PHP, HTML, CSS, JavaScript a další.


Přihlásit se Registrace  

6. díl - PHP injection - co je to a co s tím

Zpět do sekce Jednoduchý dynamický web v PHP

V minulém dílu seriálu o PHP jsme si vysvětlili soubory a cykly, řekli jsme si něco o cyklech a načítání souborů do proměnných. V předminulém článku jsem se zmínil o tom, že na adresní řádek není spoleh. Teď máme všechen potřebný arzenál po ruce. Jdeme na věc...

Možné hrozby

Do adresního řádku si může kdokoli cokoli ručně napsat, případně může zveřejnit libovolně zkonstruovaný odkaz. Možná si říkáte: no a co? Stránku mi nepředělá a je jeho věc, co se mu v prohlížeči zobrazí, ne? Ovšem jednou se může třeba na vašem oblíbeném fóru objevit vzkaz:

Hele, mrkněte se na Mrakoplašův blog - to je hustý, co?
[url]http://mra­koplas.nu.am/in­dex.php?stran­ka=http://www­.pecko.com/har­dcore.html&ti­tulek=Co%20jse­m%20delal%20o%20pr­azdninach[/ur­l]

Zrovna tohle je celkem neškodný vtípek, ale kdyby tak vypadala internetová banka a někdo by si tímhle způsobem vytáhl ze zákazníků přihlašovací údaje, to by byl prů...duch. Této technice útoku na stránky se říká PHP injection a obrana proti ní je základ, bez kterého se neobejdeme.

Jestli pro vkládání obsahu používáte pouze příkazy include a require, máte obvykle o starost míň, protože vkládání z jiných serverů bývá na většině serverů zakázané. Ale kdyby zakázané nebylo nebo pokud soubory načítáte přes file_get_contents nebo něco podobného, čtěte dál.

Další hrozba se skrývá v zobrazení souborů, které jsou nějakým způsobem citlivé, např. soubor .htpasswd obsahující hesla velmi jednoduše zobrazíme v příkladu zminula touto adresou:

domena.cz/index.php?stranka=.htpasswd

Nepomůže nám ani, když budeme v jiné složce, složku může útočník jednoduše změnit takto:

domena.cz/index.php?stranka=../.htpasswd

Útočník se stále nedostane k PHP kódu. Pokud ovšem toto udělá např. u souboru, kterým stahujeme soubory z našeho webu a který obsahuje funkci jako readfile, může si stáhnout dokonce naše zdrojové PHP kódy, zjistí heslo do databáze, emaily a hesla uživatelů, no jéje...

Zabezpečení

Je potřeba nějak zařídit, aby šly zobrazovat jenom ty stránky, u kterých to dovolíme. Způsobů, jak to konkrétně naprogramovat, je nepřeberně, ukážeme si jenom dva nejjednodušší.

1. Natvrdo nakódovaný seznam stránek

Vtip je v tom, že do adresního řádku nepíšeme přímo jména souborů, ale jenom nějaké zástupné identifikátory (teoreticky sice můžou být stejné, ale není to nutné). Ve skriptu potom pomocí příkazu switch určíme, kterému souboru zadaný parametr odpovídá:

switch($_GET['stranka'])
 {
 case 'motylci': $soubor='motyli.htm';
                 $titulek='Sbírka motýlů';
                 break;
 case 'zabky': $soubor='zaby.htm';
               $titulek='Sbírka žab';
               break;
 default: $soubor='zakazano.htm';
 };

A máme tu nový příkaz: switch. Slouží k rozvětvení běhu skriptu do několika možných cest v závislosti na hodnotě nějaké proměnné, kterou uvedeme v závorce za slovem switch (v našem případě $_GET['stranka']). Zbytek příkazu je uzavřen do složených závorek. Jednotlivé možnosti začínají slovem case, následuje požadovaná hodnota proměnné, dvojtečka a za ní příkazy, které se mají v tomto případě vykonat. Za poslední z nich je potřeba vždycky dát break, který ze switche vyskočí, jinak by se plynule pokračovalo příkazy z následující možnosti, až do konce (což se někdy může hodit, proto to tak je). V našem příkladě jsme si kromě jména souboru nastavili i titulek, abychom ho nemuseli pracně psát do odkazů. Na konec můžete dát slovo default a příkazy, které se mají provést v případě, že hodnota proměnné neodpovídá žádné z uvedených možností. Když tam default není, neprovede se v takovém případě nic. V našem případě jsme si připravili soubor zakazano.htm, ve kterém bude nejspíš nějaké upozornění na chybu v adrese.

Následné využití proměnných $soubor a $titulek už je doufám jasné.

2. Seznam stránek v nějakém samostatném souboru

Switch je jednoduchý a univerzální, ale nutí nás při každém přidání nové stránky přepisovat skripty a tím se pracnost dostává zpátky na úroveň ruční administrace, což nechceme. Výhodnější je mít seznam dovolených jmen uložený v samostatném souboru (nebo v databázi), který si skript přečte a prohledá. Vytvoření takového seznamu je velice jednoduchá záležitost, protože se dá zautomatizovat (například příkazem DIR). Seznam nahrajeme na server (teoreticky to nemusí dělat jenom administrátor, ale pozor na kolize, kdyby dva lidé těsně po sobě nahráli každý svoji verzi souboru) a do hlavního skriptu napíšeme něco ve smyslu:

$auto_detect_line_endings=1;
$jmena=file('seznam.txt',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if($jmena and in_array($_GET['stranka'],$jmena))
 {...v pořádku, stránku můžeme zobrazit...}
else
 {...chyba, tuhle stránku v seznamu nemáme...};

Příkaz na druhém řádku načte seznam ze souboru do pole $jmena, kde v každém prvku bude jedno jméno. Funkci file a její parametry jsme si vysvětlili předminule, stejně jako význam toho prvního řádku.

Třetí řádek rozhoduje, jestli stránku zobrazíme nebo ne. První podmínka je, že proměnná $jmena nesmí být prázdná (prázdná by byla, kdyby se seznam z nějakého důvodu nepovedlo načíst) - v PHP stejně jako v C znamená jakákoli nenulová hodnota ekvivalent logického "true", takže pokud v poli aspoň něco je, je to OK. Druhá podmínka je, že zadané jméno stránky musí být v seznamu. Na to použijeme funkci in_array(), která nám to řekne. Její první parametr je hodnota, kterou v poli hledáme, druhý je to pole a výstupem je true (je tam) nebo false (není tam). Když jsou obě podmínky splněny, stránku vložíme.

Ještě trochu teorie k logickým výrazům. Interpret je vyhodnocuje postupně podle závorek a priority operátorů, v případě stejné priority potom zleva doprava. Jakmile je mu jasný celkový výsledek výrazu, vyhodnocování ukončí (stejně jako např. v Pascalu). Ve výše uvedeném příkladu tedy nejdříve vyhodnotí prázdnost/nepráz­dnost pole $jmena a kdyby mu vyšlo false, nebude už ani volat in_array, protože ví, že by na výsledku toho andu nic nezměnila.

Teoreticky bychom místo in_array mohli pole klasicky (tj. pomocí for nebo foreach) projít prvek po prvku a postupně je porovnávat se zadaným jménem. Ale bylo by to pomalejší, protože by PHP muselo pracně interpretovat cyklus, zatímco předdefinované funkce jsou v něm zakompilované a pracují s daty přímo.

Ještě by to možná chtělo vysvětlení, proč jsme se při načítání seznamu tak moc chtěli zbavit konců řádků. Je to jednoduché - "stranka.htm\n" je úplně jiný řetězec než "stranka.htm", takže by to in_array nevyhodnotila jako shodu.

V praxi se obvykle seznamy stránek neukládají do souboru, ale do databáze, kde je kromě jména souboru rovnou i titulek, jméno autora a celá řada dalších doplňujících metadat. Často tam bývá uložen i samotný obsah stránky. Výhodou databází je, že bezpečně řeší současné přístupy od několika uživatelů, což je pro větší redakční systémy nezbytné. Databáze si popíšeme v dalších dílech tohoto seriálu. Začneme hned v tom příštím, ve kterém si vytvoříme jednoduché počítadlo návštěv.

Komu to dneska nestačilo, může se podívat na alternativní verzi tohoto trojčlánku s pár bonusy navíc. Příště se podíváme na databáze v PHP.


 

Autor: Mircosoft
Autor se věnuje amatérskému tvoření v Turbo Pascalu, Assembleru a PHP a profesionálnímu šťourání v jiném Assembleru, Rexxu, Cobolu a podobných obskurnostech.

Jak se vám líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Předchozí článek
Další způsoby načítání souborů
Druhá půlka tutoriálu o dynamickém skládání stránek: načítání souborů do proměnných a jejich následné zpracování.
Všechny články v sekci
Jednoduchý dynamický web v PHP
V seriálu nejprve v PHP vytvoříme jednoduché doplňky jako webové formuláře, počítadla, ankety a knihy návštev. Nakonec si vytvoříme redakční systém.
Další článek
Začínáme s databázemi
Další část seriálu o tvorbě dynamických stránek. Dozvíme se, co to je databáze MySQL a jak se do ní dostat.


 

 

Vaše komentáře:

05.02.2012 23:03:27
Avatar
Dangeres
Neregistrovaný

Ahoj, bude ešte pokračovať tento seriál ? :)


Odpovědět
06.02.2012 11:35:38
Avatar
Mircosoft
Redaktor
Skill: Core 2 Duo
DotDotDotDotDotDotDotDotDotDot
26.06.2012 16:16:28
Avatar
sdraco
Moderátor
Skill: Kvantový počítač
DotDotDotDotDotDotDotDotDotDot

Tady si nejsem jistý, jestli to stejně nejde nějak nabourat nějakými speciálními znaky. Když už, tak bych to kontroloval na [A-Za-z] případně pomlčku


Odpovědět   i++; | i--; ( +1 )
You only get one shot, do not miss your chance to blow. This opportunity comes once in a lifetime.

 

Zobrazeno 3 z 3 zpráv


Přidat novou zprávu

Avatar
Neregistrovaný

Pro výhody se přihlaš. Pokud ještě nemáš účet, zaregistruj se.

Jméno:
E-mail:
Web:

Šťastný Smutný S vyplazeným jazykem Mrkající Smějící se Plačící Cool Nemocný Naštvaný S brýlemi Stydící se On to nebyl Překvapený Hodně překvapený Šokovaný Srdce sdraco
Vložení obrázků Obrázky mohou nahrávat pouze registrovaní uživatelé
Vložení dlouhého zdrojáku Pouze pro registrované

 

Pro ověření prosím zaškrtněte pravdivá tvrzení:
Registrovaní uživatelé se tímto zdržovat nemusí. Zaregistrovat se

Píši proto, že zpráva má užitečnou hodnotu
Budu respektovat pravidla
Jsem člověk
Píši zprávu i přesto, že nemá žádný význam