8. óra – Weboldalak biztonsága
Gyimesi Ákos
[email protected] http://webprog.gy-i-m.com
Bevezetés ●
Kiket fenyeget veszély? –
a weblap üzemeltetőit: ● ● ●
–
a szerver üzemeltetőit: ● ●
–
adminisztrátori jogosultságok szerzése adminisztrátori funkciók végrehajtása (pl. törlés) tetszőleges kód futtatása PHP-ban vagy adatbázisban hozzáférés érzékeny fájlokhoz (pl. /etc/passwd) hozzáférés más honlapokhoz (shared hosting)
a felhasználókat: ● ●
jelszavuk, session-jük ellopása (XSS) nem kívánt műveletek végrehajttatása (CSRF)
Védekezés - alapok
Alapszabály:
MINDEN usertől jövő input gyanús!
Súlyos hiba 1: jogosultságkezelés ●
Súlyos hiba 1: nincs jogosultságkezelés PHP oldalon
Ha csak ennyi a jogosultságkezelés, azt a hülye is ki tudja használni...
Súlyos hiba 1: jogosultságkezelés ●
Ugyanez hidden mezőkkel:
Hála a Firebug-nak, ezt egy hülye is át tudja írni...
Súlyos hiba 1: jogosultságkezelés ●
Ugyanez egy „jó” keretrendszerrel:
templates/register.php:
register.php: $user = new User($_POST['user']); $user->insert();
new User() ész nélkül elfogad minden attribútumot => isAdmin=1-et is, ha a böngésző azt átadja
Súlyos hiba 1: jogosultságkezelés ●
Súlyos hiba 1. elkerülése: –
minden adatbázisművelet előtt ellenőrizzünk jogosultságot (a session-ből)
–
adatbázisművelet paramétereit (pl. isAdmin) szűrjük
Súlyos hiba 2: SQL injection ●
Egyik leggyakoribb támadási mód –
pedig elkerülése egyszerű: paraméteres SQL
login.php $conn->execute(”SELECT * FROM users WHERE username='$_REQUEST[user]' AND pass='$_REQUEST[pass]' ”);
legfőbb ok: programozó lustasága (1 sorral rövidebb kód...)
Súlyos hiba 2: SQL injection ●
Egyik leggyakoribb támadási mód –
pedig elkerülése egyszerű: paraméteres SQL
–
exploit is egyszerű... ● ● ●
login.php?username=admin'-login.php?username=admin'; DROP TABLES-login.php?username=admin' AND 1 OR 1='
http://xkcd.com/327
Súlyos hiba 2: SQL injection ●
Hibás védekezési módok: –
addslashes() ●
●
kijátszható: egyes karakterkódolásoknál egy betű második karaktere lehet \ vagy ' magic_quotes_sybase beállítás esetén \' helyett '' lesz...
Súlyos hiba 2: SQL injection ●
Hibás védekezési módok: –
magic_quotes ●
● ●
●
●
php.ini beállítás: minden GET és POST változóra lefut egy addslashes() ugyanúgy nem nyújt teljes védelmet ott is működik, ahol nem kéne (jelenség: input mezőkben egyszer csak megjelennek a \ karakterek...) megnehezíti az alkalmazás hordozhatóságát (vagy be van kapcsolva, vagy nincs...) PHP 6-ban (végre) eltávolítják
Súlyos hiba 2: SQL injection ●
Rendes védekezési módok: –
mysql_real_escape_string() ● ● ● ●
karakterkódolást figyelembe veszi DE: adatbázis függő kényelmetlenül hosszú a neve ;) csak akkor véd, ha a paramétert stringként használjuk! $conn->exec('SELECT * FROM news WHERE id=' . mysql_escape_string($_REQUEST['news_id']) ); exploit: http://example.com/news.php?news_id=1; DROP TABLE news
Súlyos hiba 2: SQL injection ●
Rendes védekezési módok: –
paraméteres SQL-ek ● ●
PHP5: PDO beépítve támogatja előtte: adatbázis absztrakciós réteg (pl. ADOdb) $stmt = $conn->prepare('SELECT * FROM news WHERE id=?'); $result = $stmt->execute(array( $_REQUEST['news_id'] ));
Veszélyes műveletek ●
Különösen veszélyes műveletek: –
include
–
fopen()
–
eval()
–
preg_replace, eval mód echo preg_replace('/^([0-9]*)$/e', '\\1*\\1', "16"); // 256
Ha ezek paramétereiben user input van, NAGYON gondosan validáljunk!
Veszélyes műveletek ●
Tipikus példa: include –
a honlap felépítése moduláris
–
1 bemeneti fájl (index.php), ez nyitja meg a modulokat
–
●
index.php?module=news&id=2
●
ha nincs input validáció... ●
index.php?module=../../../etc/passwd
Fájlfeltöltés ●
Fájlfeltöltésnél az alábbiakra figyeljünk: –
a célkönyvtár legyen validálva ●
–
a célkönyvtár ne legyen webről látható ● ●
–
nehogy lecserélhessen pl. egy PHP fájlt... különben feltölthet egy PHP szkriptet... vagy: szűrjük a fájlok kiterjesztését, tartalmát
a célfájl nevében ne lehessen /, .., \
register_globals ●
register_globals – a 2. leggyűlöltebb PHP funkció –
ez is php.ini beállítás (vagy van, vagy nincs)
–
ha On, akkor minden GET-ben vagy POST-ban érkező paraméter globális változó lesz
–
sok régi kód számít rá
register_globals ●
register_globals – Miért veszélyes?
delete_product.php: $user = getCurrentUser(); if ($user->isAdmin) { $isAdmin = true; } if ($isAdmin && isset($_GET['id']) { deleteProduct($_GET['id']); }
exploit: delete_product.php?isAdmin=1&id=123
További veszélyek ●
Mindez szinte elegendő lenne, ha ... –
a felhasználókat nem kellene megvédeni egymástól
–
ha a szervert nem kellene megvédeni a programozóktól
–
ha nem lennének spammerek...
Cross Site Scripting ●
Felhasználók egymás ellen #1 – Cross Site Scripting –
rövidítése: CSS, XSS
–
lényege: kód injektálás az oldalra úgy, hogy ● ● ●
azt más felhasználó megnézze ezáltal az ő böngészőjében lefusson a kód hatása: – – –
idegesítő működés (pl. JavaScript alert-ek) bizalmas adatok ellopása (ami az ő böngészőjében látszik, azt látja a JavaScript is) esetleg: tetszőleges fájl elérése a felhasználó gépén (böngészőhibák kihasználása)
Cross Site Scripting ●
Tipikus példa: user fórum –
a beküldött üzenetek nincsenek (vagy rosszul vannak) escape-elve
–
a támadó beküld egy JavaScript kódot, ami ● ●
●
kiolvassa a felhasználó session cookie-ját konstruál egy láthatatlan űrlapot a HTML oldalon, mely a támadó szerverére mutat submit-olja az űrlapot
Cross Site Scripting ●
Védekezés XSS ellen: –
escape-elés: output oldalon megjelenő input-ot szűrjük
–
sima htmlspecialchars() nem elég: ●
●
ugyanaz a karakterkódolásos probléma, mint addslashes()-nél megoldás:
htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
Cross Site Scripting ●
Védekezés XSS + session-lopás ellen: –
a session csak 1db IP címről működjön ● ●
–
NAT-olt hálózaton nem nyújt védelmet mobil eszközök gyakran válthatnak hálózatot...
session ID-t még véletlenül se tegyük URL-be! ● ●
sok weboldal oda teszi, ha nincs cookie támogatás... PHP is alapértelmezetten így működik (kikapcsolható)
Cross Site Request Forgery ●
Felhasználók egymás ellen #1 – Cross Site Request Forgery –
lényege: a felhasználót rávenni arra, hogy egy linkre vagy űrlapra kattintson
–
a link vagy űrlap a támadni kívánt oldalra visz, ahol egy műveletet hajt végre (pl. jelszóváltoztatás)
–
mivel a felhasználó be van jelentkezve az oldalra, az ő nevében hajtódik végre a lekérés
Cross Site Request Forgery ●
CSRF – Példák: –
email-ben link:
http://example.com/chpass.php?newpass=cracked –
ha ez feltűnne:
http://tinyurl.com/dk2orr –
de még egy kattintás sem kell hozzá:
Sose engedjünk ilyen műveleteket $_GET-en keresztül!
Cross Site Request Forgery ●
A $_POST-ra áttérés még nem teljes védelem: –
●
a linkelt oldalon ugyanúgy lehet egy űrlap, amit egy JavaScript automatikusan elküld
Megoldás: ne lehessen ilyen oldalt kreálni!
Cross Site Request Forgery ●
Védekezés CSRF ellen: –
HTTP referer vizsgálat: ●
●
●
–
ez egy HTTP input header: honnan jön a kérés (hol volt a link, amire kattintottak) sajnos ezt ki lehet kapcsolni böngészőben + proxy-k is elronthatják + HTTPS-ről nem működik... Flash-ben kijátszható :(
session élettartamának korlátozása ●
nem ad teljes védelmet
Cross Site Request Forgery ●
Védekezés CSRF ellen: –
összes módosító jellegű kérés authentikálása: ● ●
●
●
–
session-höz egy titkos azonosítót rendelünk ezt az azonosítót minden űrlapba beletesszük hidden mezőként csak akkor fogadunk el egy űrlap kérést, ha szerepel benne ez az azonosító ezt a támadó csak akkor tudja, ha lehallgatta a forgalmat (ennyi erővel viszont a jelszavunkat is lehallgathatta volna...)
fontos műveleteknél: captcha, SMS authentikáció stb.
Szerver-szintű védekezés ●
Shared hosting problémák: –
sok webes felhasználó 1 szerveren ● ●
–
ezek egymást is támadhatják ... vagy az egész rendszert
kiszolgálás általában: Apache+mod_php ●
minden PHP szkript a www_data user nevében fut...
Szerver-szintű védekezés ●
Egy elhibázott próbálkozás: PHP safe mode –
ez is egy php.ini beállítás
–
PHP hívásokat letilt, vagy hatókörüket korlátozza: ●
●
●
●
megadható a tiltott függvények listája (tipikusan: system, exec stb.) fopen(), readfile() stb: beállítható egy basedir, amin kívül nem nyúlhat csak olyan fájlok nyithatók meg, melyek tulajdonosa megegyezik a PHP szkript tulajdonosával megadható egy alapkönyvtár, amin kívül az fopen() stb. nem nyúlhat
Szerver-szintű védekezés ●
Problémák a safe mode-al: –
.htaccess-el sokszor kikapcsolható
–
néhány hívás korlátozása hiányos => ki lehet törni a safe mode-ból
–
jogosultságproblémák fájlfeltöltésnél: ●
●
egy fájl csak úgy nyitható meg, ha tulajdonosa megegyezik a PHP szkript tulajdonosával de a feltöltött fájlok a www_data user nevében jönnek létre...
–
mail() korlátozások => hiányos paraméterezés esetén nincs hibajelzés, de nem megy ki levél
–
külső programok hívása lehetetlenné válik
Szerver-szintű védekezés ●
Valódi megoldás: suPHP –
minden PHP szkript a szkript tulajdonosa nevében fut
–
ehhez kell: mod_suphp + egy setuid-os (de apró) program
–
elég új (első publikus verzió: 2006), ezért sok helyen még nincs bevezetve
Szerver-szintű védekezés ●
Suhosin-patch (Hardened PHP): –
alacsony szinten: védelem a PHP Core-ban ● ●
–
buffer overflow egyéb potenciális, esetleg nem ismert bug-ok
magas szintű védelem: ● ●
● ●
néhány veszélyes művelet (pl. eval) kikapcsolható néhány további ismert támadási mód elleni védekezés (pl. HTTP response splitting attack) session adatok titkosított tárolása állítható log-olás
Összefoglalás ●
Védelemre szorul: –
a programozó a hacker-ektől
–
az adminisztrátor a programozótól
–
a felhasználók egymástól
Összefoglalás ●
Nem árt, ha paranoiásak vagyunk, mert: –
a böngésző „veszélyes üzem” ●
–
a felhasználó könnyen félrevezethető ●
–
pl. JavaScript, Flash miatt ismerős nevében kapott email...
sok betörés kevés próbálgatással, akár automatizáltan végrehajtható ●
pl. Wordpress worm
És akkor még nem is beszéltünk a böngészőhibákról!...