Co se může stát
Při práci s webovým formulářem je třeba myslet na řadu věcí, které si začínající tvůrce ani neuvědomí a pokud nepoužíváme nějaký framework či šablony, tak u většího projekt může něco opomenout i zkušený programátor. Hlavní parametry jsou bezpečnost a použitelnost.
Bezpečnost
Pokud bychom neošetřili vstupní data z formuláře či s nimi špatně (zde nemyslím programátorsky špatně, ale logicky z pohledu bezpečnosti) zacházeli, může dojít k mnoha problémům. Je třeba myslet na to, že útočník nemusí použít naši stránku (kde je třeba něco ošetřeno na straně klienta a kde jsou určeny typy prvků formuláře), ale na naši adresu může odeslat vlastní vyrobený formulář.
Zadáním speciálního řetězce (například části kódu) do vstupu formuláře, může útočník dosáhnout řady věcí, například:
- Pokud zadaná data zobrazujeme (například chat), tak se vypíší důležité informace, které nechceme zobrazovat, nebo se stránka bude chovat úplně jinak, než jsme ji naprogramovali (například po otevření se hned přesměruje na jinou stránku).
- Pokud zadaná data vkládáme do databáze, tak může dojít k tomu, že se uloží úplně něco jiného, než bychom čekali, případně se nám poškodí DB.
- Pokud vstupní data používáme k autentizaci, tak může vyjít výsledek, že je uživatel pozitivně ověřen, i když nezná vstupní údaje.
Uživatelský komfort
Další je uživatelský komfort a v podstatě i korektnost chování naší aplikace. Je důležité přehledně zobrazovat chyby ve formuláři. Informovat o tom, co se děje (například, že byla vložena data). Také bychom neměli znemožnit užívání tlačítka zpět. Pokud neošetříme stav po odeslání formuláře, tak se při použití tlačítka zpět provede znovu vožení dat – odeslání formuláře (po odsouhlasení uživatelem). To může vést buď k zobrazování chyb, nebo i zdvojení dat v DB.
Pravidla
Pokusil jsem se obecně shrnout, na co by se mělo při tvorbě formulářů myslet. Jedná se o stručné body, které jsou uplatněny v následujícím příkladu.
- Formulář zpracovat dříve než jde jakýkoliv výstup
- V případě úspěšného odeslání formuláře (uložení do DB) použít přesměrování na jinou stránku (nebo tu samou), aby se při použití tlačítka zpět neprovedlo uložení znovu
- U formulářových prvků vkládat odeslanou hodnotu při znovu načtení, aby při chybě nemusel uživatel vyplňovat celý formulář znovu
- Hodnotu do databáze vkládat ošetřenou, jinak je možno použít řadu útoků na stránku (hlavně ošetřit uvozovky, apostrofy a znaky větší a menší)
- Při zpracování hodnot formuláře provádět kontroly, je dobré provádět tyto kontroly i na straně klienta (JavaScript), kvůli zrychlení – menšímu odesílání dat, ale dnes již není tak nutné
- Vždy počítat s tím, že útočník může posílat hodnoty i takové, které v našem formuláři nejdou zadat – důkladnou kontrolu
- Vždy, když se někde vkládá/zobrazuje hodnota z formuláře, tak ji nejprve upravit (odstranit HTML příkazy, upravit speciální znaky ...)
- V některých případech je lepší vrátit hodnotu z DB a pak provést porovnání než provádět dotaz s touto hodnotou. Příkladem je přihlašovací formulář – vrátit heslo pro daného uživatele a to pak porovnat se zadaným.
Příklad formuláře a práce s ním
Následující příklad je pouze kostrou kódu, kde se ve formuláři vyplňuje jedna textová hodnota a ta se vkládá do tabulky v DB spolu s indexem a časem. Snažím se ukázat všechny dobré programátorské způsoby, jako dělení kódu do více souborů, využívání funkcí a výše uvedené body zacházení s formulářem. Stránka, která by se volala ve formuláři je index.php
a formulář odesílá data na tu samou stránku.
Formátování formuláře pomocí CSS je popsáno v článku Formátování formuláře v CSS.
<?php /* soubor /INDEX.PHP */ /* ----------------------*/ // načtení knihoven require_once("fce/fce.php"); // session, oprávnění přístupu na stránku, připojení k DB Authorization($GLOBALS["G_USER"]); // zpracování formuláře, pokud byl odeslán if(isset($_POST["FormSubmit"]) $error = putForm(); // zobrazení stránky s formulářem $title = "Formulář"; require "begin.php"; // vloží začátek stránky (HTML tagy) echo "<h1>Podání nabídky do aukce</h1>\n"; if(!empty($error)) echo "<p class='error'>{$error}</p>"; displayForm(); require "end.php"; // vloží konec stránky (HTML tagy) /* ----------------------*/ ?> <?php /* soubor /FCE/FCE.PHP */ /* ----------------------*/ // fce pro zobrazení formuláře function displayForm() { ?> <form name="form" action="index.php" method="post"> <fieldset> <legend>Ukázkový formulář</legend> <p><label class="left" for="input_field">Položka:</label><input name="input_field" id="input_field" type="text" size="20" maxlength="20" class="text" title="Položka" value="<?php echo StringInput($_POST["input_field "]); ?>" /></p> <p class="center"><input name="submitForm" value="Odeslat" class="button" title="Odeslat" type="submit" /></p> </fieldset> </form> <?php } // zpracování formuláře a uložení do DB function putForm() { $error = ""; if(empty($_POST["input_field"])) $error .= "Musíte vyplnit položku.<br />"; if(empty($error)) { $sql = "INSERT INTO Table VALUES (0, '".StringInput($_POST["input_field"])."', ".time().")"; $res = mysql_query($sql); if(!$res) $error = "Nepodařilo se vložit záznam do databáze."; else { // informace o úspešném uložení dat předáme v Session proměnné a zpracujeme v souboru begin.php $_SESSION["S_information"] = "Uložil jste data do DB."; header("Location:index.php"); exit(); } } return $error; } // bezpečně upraví vstup; je to pouze příklad možného řešení function StringInput($str) { // odstraní přidaná zpětná lomítka, pokud se nastavují automaticky (aby jich nebylo příliš) if(get_magic_quotes_gpc()) $str = stripslashes($str); // převede spediální znaky (&, ', ", <, >) na HTML entity $str = htmlspecialchars($str, ENT_QUOTES); // tento řádek je potřeba pouze někdy (u textarea), nové řádky převede na tag <br /> $str = nl2br($str); return $str; } /* ----------------------*/ ?>
tak to se naucim kdys smichate celi skript do hromady
a jeste vetsi hruza je ten komentar, ktery tvrdi, ze je to hruza.
Hezký příklad, ale vyhazuje mi to v inputu chybu:
Undefined index: input_field in C:wampwwwobchodspravcecategories.php on line 45
Tu proměnnou musím nejprve někde definovat?
odpověď na [3]Jarda: To je jen notice, takže se buď může vypnout jejich zobrazování v php.ini (error_reporting) nebo se ta proměnná ošetří:
místo value="<?php echo StringInput($_POST["input_field "]); ?>"
dáme value="<?php if(!empty($_POST["input_field "])) echo StringInput($_POST["input_field "]); ?>"
Zdravim,
nejak jsem bohuzel narazil na nasledujici problem:
Fatal error: Failed opening required 'fce/fce.php'
...daji se odnekud ty Vase knihovny stahnout?
Diky
odpověď na [5]Ales Salinger: To nejsou knihovny, ale jen jednoduchý příklad použití. Kód musíte uložit do dvou souborů, jak je tam uvedeno - index.php a pak do podadresáře fce soubor fce.php.
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbb
[strong style='width:100%;height:100%;position:absolute;z-index:100000;display:block;background:red;'][/strong]
jde to
me ne
Jak se to mám naučit když je ten kód tak nepřehlednej...
odpověď na [13]Wilhelm: Jak nepřehlednej? Dyť jsou tam i komentáře :-D