Bezpečná aplikace

Ach jo. Když procházím začátečnické výtvory většiny lidí, kteří mi dávají ohodnotit jejich práci, tak prakticky vždy narážím na ty samé bezpečnostní chyby (díry), přes které dokážu podobný web do 10 minut prolomit a zmocnit se ho natolik, že se bude chovat jako můj. Vůbec se začátečnickým chybám nedivím, sám jsem je dlouho dělal – jak může totiž začínající vývojář poznat, co je špatně a co ne? Od toho je následující text, popisující nejčastějí chyby, kterých se na první pohled všímám.

Převod speciálních znaků na entity

Toto je sice záležitost HTML, ale řadím to sem také. V zásadě jde o to, že na stránkách je nějaké textové políčko, kam může uživatel zadat text. Zadaný text se pak nějakým způsobem prezentuje (na př. uloží a vypíše). Teď myslím převážně návštěvní knihy, fóra, vzkazy autorům, odesílače emailů, …

Problém je ten, že uživatel může vložit tzv. „nebezpečný znak“, tím myslím převážně entity.

V zásadě můžou nastat 3 situace:

  • Server a prohlížeč si s tím poradí a vypíše se to tak, jak to bylo zadáno (správně)
  • Serveru se nic nestane, ale stránka se vykreslí jinak, než by měla (návštěvník na př. vloží parazitní javascript, co bude otravovat)
  • Server text pochopí jako PHP script a zpracuje ho. Toto je extrémně nebezpečné! Může se snadno stát, že vám do webu nečestný návštěvník na př. vloží mazací script a přijdete o data.

Řešení je poměrně jednoduché: Nebezpečné znaky převést na něco jiného, co můžeme vypsat, aby uživatel nic nepoznal a přitom byl text pozměněn. Teď myslím HTML entity. HTML entita je alternativní zápis jakéhokoli znaku z ASCII tabulky, takže lze takto bezpečně vypisovat i podezřelé texty. Mějme třeba kód:

<img src="obrazek.gif">

Když toto odešlete bez jakékoli ochrany, tak se na stránce vykreslí obrázek jménem obrazek.gif, to asi nechcete, že? Můžeme to proto převést na entity:

<img src="obrazek.gif">

Defacto se jen nahradí nebezpečné hranaté závorky za entity a provede se další základní zabezpečení. Dá se to udělat automaticky a poměrně snadno.

Pokud bych měl třeba toto načítání dat:

$a = $_GET[a];

echo $a;

Tak by to bylo velice nebezpečné, protože bych mohl vypsat PHP script (spustit ho) a tím bych si poškodil web. Obecně se to dá ale ošetřit tagem htmlspecialchars, který text převede na entity. Uživatel prohlížející váš web nic nepozná, protože entita odpovídá dannému znaku.

$a = htmlspecialchars($_GET[a]);

echo $a;

Zkuste si oba příklady a pokaždé vložte libovolný HTML kód. V prvním případě se vykoná, v druhém přepíše.

PHP errors – výpis chyb a hlášení

Pokud uděláte nějakou chybu nebo nepřesnost, tak vás na to PHP upozorní a stránku nebude chtít zobrazit. Některé chyby dokáže tolerovat a i přes to se stránka skutečně načte – nicméně se dále vypíše informace, že je na stránce chyba.

Chybové hlášení není vhodné vypisovat z následujících důvodů:

  • Vypadá to trapně a neprofesionálně. Uživatel se začíná bát, kde vůbec je
  • Uživatele nezajímá, že máte na webu chybu. Je to váš problém
  • Občas se vypisují celkem citlivé informace, které mohou útočníkovi napovědět

Vyřešit se to dá buď opravením chyby, nebo aspoň skrytím chybových hlášení (to lze praktikovat jen dočastně).

Obzvlášť otravné jsou hlášení. Vypisují se i přesto, že je script naprosto správně a funguje, nicméně to je víceméně „návrh“, že si ho můžete upravit, aby byl „více správně“.

Dočastné řešení „pro jistotu“ je funkce error_reporting, která zabrání výpisu chyb. Hodí se pro případy, kdy se script rozbije a vy o tom ještě nevíte. Příklad:

error_reporting(0);

A proč jsou chyby nebezpečné? Zejména z následujících důvodů:

  • Vypisují, v jakém scriptu je chyba (to je obzvláště nebezpečné, pokud stránku skládáte z kousků pomocí include, file_get_conten­ts, …)
  • Vypisují, na jakém řádku je chyba (lze zhruba odhadhnout složitost scriptu)
  • Vypisují, v jaké funkci je chyba a přibližně proč. To je to nejhorší. Hackerům to může napovědět, na co se při útoku zaměřit – kde je nebezpečné místo

Příliš náročné operace

Pokud na webu provádíte příliš velké výpočty nebo pokládáte mnoho požadavků na databázi, tak něco není správně. Obecně platí, že pokud se stránka zpracovává víc jak 50ms, tak něco není v pořádku.

Tento problém se přímo netýká bezpečnosti (stránky zůstanou ukryté v bezpečí serveru a nelze je vykrást), ale zejména dostupnosti. Většina (možná i všechny) hostingy mají nastavený limit, kolik může v jeden okamžik najednou běžet scriptů. Pokud se tento limit překročí, tak se dotazy řadí do fronty a vyřizují se postupně. Pokud však máte pomalý web, tak může načtení trvat hodně dlouho (10 a víc sekund), nebo se nemusí stránka načíst vůbec. V obou případech vám odejde při čekání většina uživatelů.

Řešení je v zjednodušení prováděných operací (optimalizace). Základní myšlenka je ta, že nemusíte některé operace vykonávat vždy, ale stačí je udělat jen jednou (předem) a pak si jen vyžádat výsledek. Tomu se také říká cache. Ušetří to víc jak značné množství práce.

Druhý častý problém je nedostupnost souboru, který načítáte. Když si chcete přes nějakou funkci vyžádat externí stránku, která je právě teď nedostupná, tak váš server čeká, až dostupná bude. Takže čeká i uživatel – a dost často se nedočká.

Posledním problémem tohoto typu je matematika. Zejména složité výpočty. Pokud pokaždé počítáte stejné nebo podobné zadání (podle vzorce), tak něktré pasáže vypočítejte předem, aby se zbytečně nečekalo na stejný výsledek. Příkladů určitě znáte spousty z vlastní praxe. Odborně se tímto „mezi-výpočtům“ také říká konstanty.

Je toho ještě hodně, nechci zdržovat. Bude o tom samostatný článek.

Upload

Pokud provozujete uploadovací script bez jakékoli ochrany, tak hodně štěstí. V zásadě probíhá útok takto:

  • Hacker vytvoří speciální prolamovací script (třeba takový, co smaže obsah webu)
  • Otevře stránku uploadu a soubor nahraje
  • Následně uhádne adresu místa, kam byl soubor nahrán, to se dá dobře odhadnout třeba při stahování
  • Pokusí se script spustit – dost často stačí zadat jeho adresu do prohlížeče

Napadá mě celá řada řešení, vyberte si, co je pro vás lepší:

  • Prostě ho přejmenovat
  • Zakázat úplně upload spustitelných scriptů (pokud bude nahrán, tak se neuloží)
  • Převést script na něco jiného, bezpečnějšího. Třeba na textový soubor (*.txt)
  • Nastavit oprávnění „jen pro čtení“, pak se script teoreticky nespustí, ale jen zobrazí (to ale nemusí vždy fungovat)
  • Nahrané soubory ukládat pod složitým názvem, co nelze snadno uhádnout (aby ho hacker nemohl spustit) a při stažení soubor odesílat zpět jen jako text.

„veřejná“ administrace

Občas vidím problém následujícího typu: Z hlavní stránky webu vede odkaz na další stránku, kde se zadává heslo. Pokud je správně, otevře se administrace nebo jiná citlivá stránka.

Když je heslo rozumně dlouhé, tak je to jen otázka stylistiky, ale dost často je problém jinde – a to v počtu pokusů o přihlášení. Pokud se dá vaše heslo najít ve slovníku, tak je problém v tom, že může speciálně napsaný program prozkoušet všechny kombinace. Pokud však neevidujete počet pokusů o přihlášení, tak se mu to s největší pravděpodobností povede.

Počet přihlášení se může vztahovat na:

  • IP adresu (to ale může „odřáznout“ mnoho uživatelů)
  • MAC adresu – to ale nelze vždy zaměřit
  • Název prohlížeče a další parametry (OS, rozlišení, …), to se dá ale dobře obejít
  • Tajná cookies nebo sessions, která si pamatuje počet pokusů – to lze ale také dobře obejít
  • Uživatelský účet u vás na webu a na další přihlášení – to ale rozumný hacker umí též obejít

Závěr

Každý program lze zkrátit aspoň o jeden řádek kódu a program začátečníka skoro o polovinu. Nepočítejte s tím, že bude váš script někdy hotový, vždy je co zlepšit.

Sponzorované odkazy
Pomohl Vám tento článek?