Problémy pole $_REQUEST

Jaký bezpečnostní problém má následující kód?

<?php
if (isset($_REQUEST["ulozit"])) {
	mysql_query("
		UPDATE uzivatele
		SET vek = " . intval($_REQUEST["vek"]) . "
		WHERE id = " . intval($_SESSION["uzivatel"])
	);
}
?>
<form action="" method="post">
<p>
<input type="hidden" name="ulozit" value="1" />
Věk: <input name="vek" />
<input type="submit" value="Uložit" />
</p>
</form>

Problém je ten, že pokud na stránku přijde uživatel s nastavenou cookie ulozit, tak se mu věk přenastaví, aniž by odeslal formulář. Cookie může omylem nastavit jiná část aplikace, která tento formulář nebere v potaz, ale může jít i o cílený útok – pokud aplikace běží na free-hostingu (kde se přidělují domény třetího řádu), může cookie nastavit i úplně jiná stránka. To samé platí s některými prohlížeči i u domén jako .co.uk.

V PHP 5.3 navíc vznikla direktiva request_order, pomocí které lze nastavit, co bude obsahem pole $_REQUEST. Na obsah tohoto pole se tak ani nedá spolehnout.

Když si uvědomíme, jaké metody se mají používat u webových formulářů, tak pole $_REQUEST k ničemu nepotřebujeme. Pokud odeslání formuláře vede pouze ke zobrazení stránky, použijeme metodu GET (to jsou typicky vyhledávací formuláře). Pokud odeslání formuláře způsobí změnu stavu aplikace (provedení nějaké akce), použijeme metodu POST (např. uložení záznamu, odeslání e-mailu, ale také přihlášení nebo odhlášení). No a cookies s tím nijak nesouvisí – ty slouží k ukládání informací na stranu uživatele (např. jméno vyplněné do diskusního formuláře nebo session identifikátor).

Přijďte si o tomto tématu popovídat na školení Bezpečnost PHP aplikací.

Jakub Vrána, Výuka, 17.4.2009, on-line

Diskuse

ikona v6ak:

Taky mě zajímá, k čemu tu to $_REQUEST vymysleli.
17.4.2009 03:58:20

Dundee:

Používat pole $_REQUEST považuji téměř za stejnou špatnost jako používat register_globals.
17.4.2009 04:49:54

Srigi:

Dalsi priklad nebezpecneho pouzitia $_REQUEST:

http://shiflett.org/articles/cross-site-request-forgeries
11.5.2009 12:33:21

hokuka:

doplním jeden důsledek, který mi z výše uvedeného vyplývá: když má jeden skript zpracovat třeba formulář na editaci metodou POST a zobrazení detailu přes GET pomocí parametru ID. Pak je nutné ve formuláři používat action=URL?id=5 místo input{id=5,hidden=true}. Chápu to správně že?
17.4.2009 07:16:12

ikona Jakub Vrána:

Nejlepší je používat <form action="">, tedy odesílat formulář na stejnou adresu, na které se zobrazuje. Detekci odeslání je pak možno dělat ověřením neprázdnosti pole $_POST nebo porovnáním hodnoty $_SERVER["REQUEST_METHOD"].
17.4.2009 07:20:52

dadmtb:

ked už tak ja dávam: <form action="<?php echo $["PHP_SELF"]; ?>">
17.4.2009 11:13:08

ikona Jakub Vrána:

Nejen, že to je špatně syntakticky, je to špatně i bezpečnostně. PHP_SELF může obsahovat speciální znaky jako ">, takže uvedený zápis je náchylný ke XSS. Prázdné URL je definováno v HTTP jako odkaz na aktuální dokument a všechny prohlížeče to respektují, takže není důvod to nepoužívat.
17.4.2009 11:47:52

Jan Tvrdík:

Mohl by jsi uvést příklad, jak se do $_SERVER['PHP_SELF'] můžou dostat ty speciální znaky?
17.4.2009 14:35:42

ikona Jakub Vrána:

index.php/"><script>alert('XSS');</script>

Pokud je v Apache povolena direktiva AcceptPathInfo (defaultně je), tak se celý řetězec dostane do PHP_SELF.
17.4.2009 14:38:17

Washo:

Neco jako tohle:
http://php.vrana.cz/index.php/%27%3E%3Cb%…%3E%3C/aaa%3E
?
17.4.2009 16:06:03

Martin:

Washo: pekne :)
chybka se obcas vloudi
17.4.2009 17:40:57

ikona Jakub Vrána:

Ano, něco takového :-). Děkuji za upozornění.
18.4.2009 04:02:09

Jan Tichý:

Když už, tak aspoň <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
20.4.2009 03:40:27

ikona Patrik:

Keďže výstup posielame ako obsah atribútu, je treba ošetriť aj uvodzovky, ktoré by ukončili aktuálny atribút. Prešlo by napríklad:
index.php/%22%20onclick%3D%22alert%28document.cookie%29%3B
Takže vo vnútri atribútov radšej takto:
<?php
echo htmlspecialchars($_SERVER["PHP_SELF"], ENT_QUOTES);
?>
11.9.2009 11:09:29

ikona v6ak:

Podívej se v http://cz2.php.net/manual/en/function.htmlspecialchars.php na výchozí hodnotu druhého parametru. Ošetřuje i dvojité uvozovky. Jednoduché uvozovky (apostrofy) ne. Ale to není potřeba, když je parametr vymezený uvozovkama.
11.9.2009 14:14:33

ikona Patrik:

To je pravda. Osobne som si ale zvykol v HTML escapovat vždy s ENT_QUOTES bez ohľadu na to, či používam uvodzovky alebo apostrof.
11.9.2009 15:34:29

ikona v6ak:

Není nad názornou ukázku ;-)
18.4.2009 10:52:43
avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.