Bezpečné cookies
Zřejmě každý vývojář který se alespoň trochu vrtal ve webových aplikacích přišel do styku s cookies. Bohužel, ačkoliv jsou cookies používány i k ukládání důležitých hodnot, často nejsou odpovídajícím způsobem ošetřeny.
Nejjednodušší způsob uložení cookie "mycookie" s hodnotou "myvalue" je (v PHP):
setcookie("mycookie", "myvalue");
Vzhledem k principu fungování cookie jsou tímto kódem spojeny dva důležité problémy, konkrétně:
- viditelnost - Pro uživatele není problém hodnotu cookie zjistit, což zejména u interních proměnných jako jsou například ID uživatele apod. není žádoucí. Ukládání interních proměnných v cookie sice není zrovna doporučovaný způsob, ale v některých případech se může hodit.
- modifikovatelnost - Hodnoty jsou uloženy na počítači uživatele, a uživatel je tedy může bez problémů modifikovat. Pokud se jedná o interní proměnnou (například login apod.) může se jednat o bezpečnostní riziko.
Nejdříve se podíváme na druhý uvedený problém, tj. modifikovatelnost.
Podepisování cookies
Vzhledem k tomu že cookies jsou uloženy na uživatelově počítači, nelze jejich modifikaci nijak zabránit. Finta je v tom že namísto zbytečné snahy předejít modifikaci dat stačí odhalit zda byla cookie změněna, a pokud byla tak se podle toho zařídit.
Odhalit modifikaci cookie lze například pomocí jednoduchého "digitálního podpisu" založeného na hashi (s tajným saltem). Namísto jednoduchého uložení cookie (viz. první odstavec) stačí provést toto:
$salt = 'jLcQ5a'; // tajná hodnota, slouží jako heslo
$value = 'myvalue'; // hodnota cookie
$hash = md5($salt . $value);
// uložení "podepsané" hodnoty
setcookie('mycookie', $value . ':' . $hash);
Tím je hodnota cookie doplněna o hash, který ale uživatel v případě změny hodnoty nemůže dopočítat protože nezná heslo (salt).
Během načítání hodnoty z cookie je třeba ověřit zda hodnota nebyla modifikována:
$cookie = explode(':', $_COOKIE['mycookie']);
$salt = 'jLcQ5a';
$hash = md5($salt . $cookie[0]); // kontrolní součet
// ověření kontrolního součtu
if ($hash == $cookie[1]) {
// hodnota nebyla změněna - načti hodnotu
$value = $cookie[0];
} else {
// hodnota byla změněna - logout
header('Location: /logout');
exit();
}
Díky této (byť poněkud primitivní) variantě digitálního podpisu si můžete být jisti že hodnota cookie zůstala nezměněna. V případě potřeby můžete do hashe zahrnout ještě identifikaci uživatele (například ID, login, ...) čímž zajistíte že každý uživatel bude mít unikátní "podpis" a nebude možné použít cookie jiného uživatele než pro kterého byla vygenerována.
Šifrování cookies
Dalším krokem při ochraně cookies, který řeší problém viditelnosti, je pochopitelně šifrování. Pomocí knihovny mcrypt to lze provést například takto:
$type = MCRYPT_RIJNDAEL_256; $mode = MCRYPT_MODE_ECB; $source = MCRYPT_RAND; $iv_size = mcrypt_get_iv_size($type, $mode); $iv = mcrypt_create_iv($iv_size, $source); $key = 'H90uAcV'; $value = 'myvalue'; $cryptvalue = mcrypt_encrypt($type, $key, $value, $mode, $iv);
Při načítání hodnoty je samozřejmě třeba postupovat opačně, tj. dešifrovat pomocí funkce mcrypt_decrypt.
Poznámka: Šifrování cookies rozhodně není ochrana před útoky typu "man in the middle." Cookies jsou sice šifrovány a tudíž bezpečné, ale útočník je pro útok dešifrovat nepotřebuje a zbytek komunikace šifrován není.
Šifrování samo o sobě ale samozřejmě nebrání uživateli zkusit upravit zašifrovanou hodnotu a doufat že po dešifrování nedostane nesmysly. Nezbývá tedy než zkombinovat oba předchozí postupy (šifrování a podpis), přičemž je celkem jedno zda je nejdříve cookie podepsána nebo zašifrována (osobně nejdříve podpisuji).
$type = MCRYPT_RIJNDAEL_256; $mode = MCRYPT_MODE_ECB; $source = MCRYPT_RAND; $iv_size = mcrypt_get_iv_size($type, $mode); $iv = mcrypt_create_iv($iv_size, $source); $key = 'H90uAcV'; $value = 'myvalue'; $value = $value . ':' . md5($key . $value); $cryptvalue = mcrypt_encrypt($type, $key, $value, $mode, $iv);
A při dešifrování se opět musí postupovat opačně, tj. dešifrování a ověření podpisu.




