Ukládání dat
Data jsou prakticky jediná věc, kterou můžeme na internetu nabízet. Návštěvník, přijde na náš web jenom proto, aby se dozvěděl nějakou informaci. Tato informace se zobrazuje většinou prostřednictvím internetového prohlížeče.
Ať už hovoříme o datech v podobě různých článků na osobním blogu nebo velkých rozlehlých portálech, nebo hovoříme o datech v podobě uživatelských jmen a hesel, vždy pro všechna tato data musíme najít vhodný způsob uložení na serveru.
V podstatě můžeme data podle jejich důležitosti rozdělit na dvě kategorie. První jsou data, která se generují na výstupu, a jsou běžně zobrazována návštěvníkům a uživatelům našich webových služeb. Ve druhé skupině jsou data, která se snažíme před běžnými uživateli skrýt. Taková data jsou důležitá pro běh serveru jako takového, a každá informace, která je o těchto datech možná získat nám může uškodit. Hovoříme tedy o datech například pro připojení k databázi, uživatelských heslech a jménech, o strukturách tabulek, které vytváříme apod.
V této kapitole se budeme věnovat spíše té druhé skupině, tedy datům, která se snažíme před návštěvníkem skrýt, nebo co možná nejvíc zamaskovat, neboť si vyžaduje větší pozornost než data, která jsou volně přístupná.
Budeme se tedy snažit vyvarovat obvyklých chyb, která se používají pro ukládání dat a budeme se snažit je zabezpečit.
Soubory jako úložiště dat.
Soubory jsou hojně používány jako datová úložiště. Někdy je to nevyhnutelné, jindy je to přání programátora. Většinou se jedná o .txt nebo jiné datové soubory, které jsou avšak málo, nebo vůbec zabezpečeny.
Představme si například, že máme uloženy uživatelská jména a hesla v datovém souboru někde na svém serverovém prostoru volně „pohozená“. Co nyní brání útočníkovy, aby si tento soubor otevřel? Odpověď je – „nic“. Každý si může zadat do adresního řádku v prohlížeči adresu k souboru, a tedy tento soubor otevřít a přečíst.
Pokud bychom používali textový soubor jako úložiště pro například seznam administrátorů, uživatelů, včetně jejich hesel není problém jej zobrazit. Takový soubor může vypadat následovně:
1 2 3 |
1:Petr:Novotný:petr_novotny:tajne_heslo:administrator 2:Jana:Bláhová:jana:janablahova:fotky 3:Milan:Rus:palka:clanky |
V tomto případě útočník pouze zadá přesnou adresu k danému souboru a výsledek se mu zobrazí jako výstup v prohlížeči.
Tedy například pro soubor users.txt ve složce data:
A tím lze snadno získat seznam všech uživatelů.
Tohle bylo jednoduché a snad se nenajde programátor, který by takhle nechal se povalovat data. Ale člověk nikdy neví.
Na co však programátoři často zapomínají jsou data uložená v .sql, nebo jiných souborech, která se používají pro vytváření tabulek v databázi, nebo jiné operace. Programátoři si často neuvědomují, že někdo bude hledat takovéto soubory, a víc se s nimi nezaobírají. Po provedení jeho funkce jej nechají nechráněný na webovém prostoru.
Pokud si takový soubor na internetu najdeme, můžeme se dozvědět mnoho informací, které nám mají být jinak skryty.
Schválně si vyzkoušíme vyhledat takové soubory.
K vyhledání nám pomůže zase Googole, do kterého zadáme náš dotaz.
Chceme vyhledat všechny .sql soubory na českém internetu, které má tento prohlížeč zaindexované a jsou tedy volně dostupné bez jakéhokoliv zabezpečení.
Zadejme tedy do vyhledávače řetězec:
1 |
filetype:sql site:cz |
Výsledek vyhledávání přinesl v tomto případě spousty výsledků vyhledávání.
Pokud otevřeme některý z odkazů, které našel, vidíme většinou návrhy tabulek. Tedy například:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# phpMyAdmin MySQL-Dump # version 2.2.3 # http://phpwizard.net/phpMyAdmin/ # http://phpmyadmin.sourceforge.net/ (download page) # # Host: uvdb1.globe.cz # Generation Time: Aug 29, 2002 at 04:10 PM # Server version: 3.23.49 # PHP Version: 4.1.2 # Database : `demo` # -------------------------------------------------------- # # Table structure for table `actual` # CREATE TABLE actual ( id int(11) NOT NULL auto_increment, text mediumtext, link varchar(255) default NULL, date int(11) default NULL, admin smallint(6) default NULL, status smallint(6) default NULL, ….. |
Tato informace pro mnoho z vás není moc velkým přínosem a neposkytne nám téměř žádné důležité informace. Známe sice podle všeho verzi phpmyadminu, název databáze, strukturu tabulek, ale to nám většinou moc nepomůže.
Po delším prohlížení nalezených souborů určitě narazíme na soubor podobný tomuto:
1 2 3 4 5 6 |
INSERT INTO KNIHA VALUES (9844,"Ferda malem saskem","Sejkorka"); INSERT INTO KNIHA VALUES (3254,"Slovnik","Habrny"); INSERT INTO KNIHA VALUES (634,"Patologem snadno a rychle","Kulihrach"); INSERT INTO KNIHA VALUES (2346,"Babicka","Nemcova"); INSERT INTO KNIHA VALUES (404356,"Dedecek","Polkova"); INSERT INTO KNIHA VALUES (87435,"Teticka","Bulharkova"); |
Ano, jedná se o naplnění databáze. Do tabulky kniha vkládáme informace o nějakých knihách. Konkrétně tnto soubor nám sice asi k ničemu nebude, ale určitě vás napadne, co kdybychom našli sql dotazy na plnění tabulky uživatelskými jmény a hesly.
Zadáme tedy do vyhledávače Googole řetězec:
1 |
filetype:sql site:cz insert into users |
a zobrazíme výsledek. Googole opět našel spoustu odkazů.
Hned první link je to co jsme hledali:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
INSERT INTO USERS (USER_ID, USER_LOGIN, USER_PASS, USER_RIGHTS, USER_NAME, USER_SURNAME, USER_EXPDATE) VALUES (1, 'mackousko', 'heslo1', 1, 'Peter', 'Novotny', '1.1.2006'); INSERT INTO USERS (USER_ID, USER_LOGIN, USER_PASS, USER_RIGHTS, USER_NAME, USER_SURNAME, USER_EXPDATE) VALUES (2, 'vampir', 'heslo2', 1, 'Marek', 'Novak', '1.5.2005'); INSERT INTO USERS (USER_ID, USER_LOGIN, USER_PASS, USER_RIGHTS, USER_NAME, USER_SURNAME, USER_EXPDATE) VALUES (3, 'jeff', 'heslo3', 2, 'Jozef', 'Jeffulka', '1.2.2005'); Nebo například další odkaz, vyhledaný dotazem: filetype:sql site:cz login _________________________________________________ # # Vypisuji data pro tabulku `admini` # INSERT INTO `admini` VALUES (2, 1, 2, 1094716486, '046e00d6e1439631c1eb4ec6dd1e6a7f4ee4a9be', NULL, NULL, 20041016194949, 0); INSERT INTO `admini` VALUES (7, 12, 1, 1094716486, '9391c50e0b2f7636a8c24aeff70d07c1360bda67', NULL, NULL, 20041016194949, 0); INSERT INTO `admini` VALUES (3, 6, 1, 1096482301, '11f6ad8ec52a2984abaafd7c3b516503785c2072', NULL, NULL, 20041016194949, 0); # -------------------------------------------------------- |
Pokud se nyní podíváte na adresu, uvidíte:
http://fyzweb.ms.mff.cuni.cz/test/fyzweb/databaze/050221_data.sql
Tuto adresu stačí upravit na:
http://fyzweb.ms.mff.cuni.cz/test/fyzweb/databaze/
a jak vidíte, máme štěstí. Ve složce není žádný index, zobrazí se nám tedy indexovaně všechny soubory.
Pokud bychom prohlídli všechny soubory, určitě bychom zjistili víc informací, které může útočník využít.
Je až zarážející, že někdo může něco takového nechat volně dostupné. Nyní stačí jenom najít webovou stránku pro přihlašování a vyzkoušet, jestli jsou hesla ještě aktivní (popřípadě v případě zakódovaných hesel hesla dekódovat).
A to není určitě všechno, stačí správný dotaz a můžete najít i důležitější informace.
Musíme jenom hledat.
Obrana
Pokud chcete zabezpečit svá data, nesmíte povolit nikomu jinému kromě vás, aby měl k tajným datům přístup. Čili, musíte zapříčinit to, aby v případě že se útočník pokouší k datům získat přístup, server mu to nepovolil. Na tohle existuje jednoduchý způsob ochrany. Určitě jste již slyšeli o souboru zvaném .htaccess nebo .htpasswd.
Pomocí těchto souborů můžete každou složku zabezpečit proti nežádanému vniknutí.
Možnosti .htaccess
Soubor .htaccess je soubor, který je umístěný někde na webovém prostoru. Tento soubor je serverem zpracováván při každém pokusu o načtení souboru ze složky, v níž je umístěn.
Nyní si uvedeme několik příkazů, které může .htaccess obsahovat.
Options –Indexes
Zakáže indexování obsahu složky. V praxi to znamená, že pokud by chtěl kdokoli zobrazit obsah složky, ve které není index, pak by se mu zobrazil výpis všech souborů, jak jsme si to ukazovali na předešlém příkladu.
Pokud je nastaveno Options na –Indexes, pak se tento obsah nezobrazí, a namísto toho se vypíše Error 403 – přístup odmítnut. V případě že se v této složce nachází index, pak se zobrazí index. Ale pozor, příkaz nezabrání zobrazení souborů ve složce. Pouze zakáže výpis, takže pokud by někdo zadal přímo adresu a název souboru, který chce zobrazit, dostane na výstup tento soubor bez jakýchkoliv problémů.
Deny from
Další důležitý příkaz je deny from. Pokud bychom chtěli tento příkaz přeložit do češtiny, dostali bychom výraz jako je „Přístup zamítnut pro…“. Ve skutečnosti má tento příkaz více možností jeho použití, a může nabývat několika variant svých hodnot.
- Deny from all
- Přístup zamítnut pro všechny – podobný jako Options –Indexes
- Deny from 127.0.0.1
- V tomto případě je přístup zamítnut jenom z určitě IP adresy (v tomto příkladu konkrétně 127.0.0.1). Pokud bude IP adresa jiná než 127.0.0.1, bude přístup povolen.
- Ip adresa může být navíc zadána jenom několika začátečnímy znaky. Tedy například zápis Deny from 127 způsobí, že všechny IP adresy, které začínají na 127 budou mít zakázaný přístup.
- Deny from .cz
- Způsobí zákaz pro všechny cz domény.
- Deny from www.domena.cz
- Poslední možností je omezení přístupu z nějaké konkrétní adresy. Pokud se pokusí přistupovat z URL adresy uvedené za deny, dostane hlášku o nepovoleném přístupu.
Allow
Allow je opakem příkazu Deny. Tím pádem povoluje přístup ke složce.
- from 127.0.0.1
-
- Jako parametr je IP adresa, která může indexovat složku.
– všechny možnosti allow jsou stejné jako u deny.
Order
Jak již bylo řečeno, přístup můžeme omezit pomocí alow, nebo deny. Ovšem pořadí vyhodnocování je dáno pomocí Order. Představme si například, že máme zapsán v .htaccess:
1 2 |
Allow from www.zaachi.com Deny from all |
Co by to způsobilo?
Nejprve bychom povolili přístup z jedné URL adresy, a hned jej zase zakázaly pomocí Deny from all. Tomuto chování může zabránit právě Order
Order deny, allow
– způsobí, že deny bude vyhodnoceno před allow.
1 2 3 |
Order allow, deny Deny from .cz Allow from all |
– způsobí zákaz indexování pro všechny .cz domény.
DirectoryIndex
DirectoryIndex slouží k nadefinování indexů ve složce. Využijeme ji tehdy, když budeme chtít nadefinovat větší množství indexů, které se mohou zobrazit, jako seznam.
Určitě všechno pochopíte na příkladu, tedy například:
1 |
DirecotoryIndex index.php ./../index.php im.gif ./../error.php |
V tomto případě se nebere ohled na index, ale postupuje se v pořadí jaké je uvedeno za DirectoryIndex. Tedy, nejprve se hledá index.php, pokud není nalazen, hledá se index.php v nadřazené složce, a tak dále, dokud se nedojde na konec seznamu. Pokud není nalezen ani jeden ze souborů, zobrazí se výpis souborů.
Redirect
(přesměrování) slouží k přesměrování na jinou složku, nebo soubor.
1 |
Redirect ./../index.php nebo Redirect ./../ |
V prvním případě přesměruje na soubor index.php v nadřazené složce. Ve druhém případě přesměruje do nadřazené složky.
SetEvnIf
SetEvnIf je podmíněný příkaz, který je podobný všem ostatním podmínkovým příkazům v různých jazycích. .
V tomto příkazu jsou kontrolovány atributy požadavku HTTP a následně ověřeny s podmínkou.
Pokud ji vyhovují, jsou vyhodnoceny další podmínky, například pomocí deny a allow.
Nyní si popíšeme některé užitečné vlastnosti:
- HOST – název domény hostitelského serveru.
- REQUEST_URl – část url za názvem domény. (za hostitelským serverem)
- REFERER – adresa odkud požadavek přišel
- REMOTE-ADDR – IP adresa
A nyní si můžeme ukázat příkaz v praxi. Vytvoříme si tedy podmínku, která nám v případě že se nepřistupuje z naší domény zakáže přístup:
1 2 3 4 |
SetEvnIf REFERER www.mojedomena.cz ano Order deny, allow Deny from all Allow from all evn=ano |
Všimněte si podmínky a zadané URL adresy. Podmínka musí být vždy zadána jako regulerní výraz.
Vyhodnocením nám vznikne virtuální proměnná evn a s ní můžeme dále pracovat.
Využijeme ji hned u Allow. Pokud je evn=ano – povolí se přístup, v opačném případě se přístu zamítne pomocí deny a allow výbec neproběhne.
Pokud nastavíte .htaccess, bude se vztahovat na všechny podložky, které obsahuje. Nemusíme tedy podmínky vypisovat pro všechny složky, ale stačí jej umístit do kořenové složky.
Použití .htpasswd
Zabezpečení pomocí .htpasswd je asi to nejlepší co můžete udělat. Jediné co musíte udělat, je vytvořit si soubor .htpasswd a soubor .htaccess.
Soubor .htpasswd potom obsahuje hesla, která se budou používat.
V případě zadání neplatného hesla, je vyvolán Error 401 a zobrazena zpráva o požadované autorizaci.
Takový soubor .htpasswd potom může vypadat nějak takto:
1 2 3 |
User:pass User2:pass2 User3:pass3 |
Další co musíme udělat, je vytvořit správnou podmínku v souboru .htaccess.
Všechno co musíme vytvořit jsou příkazy:
AuthUserFile ./.htpasswd
– cesta k souboru s uživatelskými hesly.
AuthGroupFile null
-soubor s rozdělením uživatelů do skupin – v našem případě nebude potřeba.
AuthName “Název”
-Název složky, nebo váš inviduální název, který se bude zobrazovat při výzvě.
AuthType Basic
-typ autorizace
require valid-user
-oznámíme, že každý uživatel bude mít vedený účet v .htpasswd
1 2 3 4 5 |
AuthUserFile ./.htpasswd AuthGroupFile null AuthName "Název " AuthType Basic require valid-user |
Hesla v souboru .htpasswd je dobré uvádět šifrovaně. Pro použití je užitečná například funkce crypt(), která slouží pro jednostranné zašifrování řetězce pomocí Unixové šifrovací metody DES nebo alternativního algoritmu obsaženého v OS a použití je velmi jednoduché:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
print 'Zadej heslo pro sifrovani:'; print ' <form method="POST" action="index.php"> <input type="text" name="pass"> <input type="submit" name="sub_mit" value="Odeslat"> </form> '; if(isset($_POST['sub_mit']) && isset($_POST['pass'])): $heslo = crypt($_POST['pass']); if (crypt($_POST['pass'], $heslo) == $heslo) print $_POST['pass'] . ' => ' . $heslo ; endif; |
Jak jsme si již řekli, při kompresi mohou být použity rozdílné šifrovací algoritmy. Proto musíme testovat jestli je heslo správně zašifrováno (DES používá totiž dvou znakový salt, ale md5 dvanáctiznakový).
Chmod
Další důležitou funkcí, která jde ale využít jenom na unixových serverech je příkaz chmod. Příkaz chmod se zadává do adresního řádku a používá se ke změně povolení souboru.
K jeho zadání můžete například využít program Total Commander, ve kterém zadáte tento příkaz po připojení na FTP server.
Povolení se zadává současně pro tři skupiny. Tyto skupiny jsou:
- uživatel
- skupina
- ostatní
Každá z těchto skupin může nabývat tří různých povolení:
- čtení (R – read)
- zápis (W – write)
- spouštění (X – execute)
Každá skupina tedy může nabývat jakákoli různá povolení a tato povolení vyjadřujeme číslí:
R -> 4
W -> 2
X -> 2
Poslední je 0 – znamená, že je soubor bez jakýchkoli práv.
Součtem těchto tří čísel získáme výsledné číslo pro povolení. Pokud tedy chceme povolit zápis a čtení, potřebujeme povolit Read a Write (4 + 2) – výsledné povolení je číslo 6.
Povolení musíme nastavit pro všechny skupiny a pro každou skupinu může být jiné.
Můžeme tedy například vytvořit povolení ve tvaru: 672
- to nám říká: uživatel má povolení ke čtení a zápisu, skupina má povolení ke čtení, zápisu a spouštění, a ostatní mají povolení pouze pro zápis.
Jestliže již umíme vytvářet podmínky pro povolení, ukážeme si, jak příkaz využít v praxi.
S příkazem jste se mohli setkat například při uploadu souborů na server, kdy jste museli povolit ve složce kam se uploaduje zápis, což není standartně na většině serverů povoleno.
Příkaz chmod se tedy zapisuje ve tvaru:
Chmod povolení soubor_nebo_složka
Tedy například:
Chmod 777 data
– tím bychom nastavili 777 pro celou složku data. Toto omezení se nyní vztahuje na všechny soubory ve složce.
Chmod můžeme ovšem používat i pro jednotlivé soubory:
Chmod 777 data.txt
– tím nastavíme práva 777 jenom pro soubor data.txt a ostatní soubory ve složce budou mít defaultní nastavení.
A konečně se dostáváme k jádru věci. Pokud máme na serveru uložen soubor, ke kterému chceme zakázat přístup, není nic jednoduššího než použít příkaz chmod.
PHP dokonce standartně obsahuje příkaz, který dokáže práva měnit. Jeho název je jak jinak než chmod.
V manuálu je popsán:
1 |
int chmod ( string filename, int mode); |
Je to tedy funkce, která vrací True nebo False, podle správného vykonání a má dva parametry. První z nich je parametr filename, který vyjadřuje jméno souboru. Druhý je mód se kterým je na daný filename použit.
Použití v praxi vypadá následovně:
1 |
chmod("data.txt", 0444); |
Tím jsme zabezpečili soubor data.txt a nastavili mu práva jenom čtení.
Důležité je si zapamatovat, že funkce považuje mode za oktanovou hodnotu, proto je nezbytné před číslo vyjadřující povolení doplnit nulu.
Další důležitá věc je, že pokud nastavíme práva, platí tyto práva pro všechny uživatele, tedy i pro nás.
Pokud bychom například nastavili souboru data.txt práva 000 a následně jej chtěli otevřít pro čtení
1 |
$f = fopen("./data.txt", "r"); |
Dostali bychom varovné hlášení:
Warning: fopen(./data.txt) [function.fopen]: failed to open stream: Permission denied in /home/www/zaachi.com/subdomains/pokus/data.php on line 2
Toto zabezpečení se nám ovšem může hodit například při vytváření záloh. Vytvoříte si zálohu databáze a uložíte ji s právy 000. To znamená, že nikdo nemá práva na nic. Pokud bychom si takový
soubor otevřeli v prohlížeči, dostali bychom zápornou odpověď.
Forbiedden
You don’t have permission to access /data.txt on this server.
P příštím článku se podíváme na ukládání dat do databází. Rozebereme si jejich výhody, ale i nevýhody.
Ahoj, v clanku je chybne uveden prikaz SetEvnIf, spravne by mel byt SetEnvIf (prohozene v-n) a dale v i promenna "evn" ma byt "env". Chvilku mi to potrapilo, kdyz jsem se to snazil implementovat, oprav to prosim pro ostatni. Jinak diky moc, hodne mi clanek pomohl.