Autor Zpráva
Milan1236000
Profil
Zdravím, zkoušel jsem u vyhledávače ošetřit vstup, ale něco mi tam nesedí. Do vyhledávače jsem vždy psal testovací řetězec: ' or 1=1;-- <a href="d.com">te "x " t</a>
Vždy zadám php skript a výstup v html.
$text = mysqli_real_escape_string($pripojeni, strip_tags($_GET['hledanytext'])); \' or 1=1;-- te \"x \" t
$text = mysqli_real_escape_string($pripojeni, htmlspecialchars($_GET['hledanytext'])); \' or 1=1;-- <a href="d.com">te "x " t</a>
$text = mysqli_real_escape_string($pripojeni, htmlspecialchars(strip_tags($_GET['hledanytext']))); \' or 1=1;-- te "x " t
$text = mysqli_real_escape_string($pripojeni, htmlspecialchars(strip_tags(trim($_GET['hledanytext'])))); \' or 1=1;-- te "x " t
$text = mysqli_real_escape_string($pripojeni, htmlspecialchars(strip_tags(trim(stripslashes($_GET['hledanytext']))))); \' or 1=1;-- te "x " t
Proč se u 1., 3. a 4. skriptu neoescapovaly uvozovky a proč se u posledního skriptu nevypsal apostrof bez zpětného lomítka?
Keeehi
Profil
Proč? To nevím, ale správné ošetření uživatelského vstupu by mělo být mysqli_real_escape_string($pripojeni, ($_GET['hledanytext']);. Z hlediska ochrany je to absolutně vše, co potřebuješ. Pro trochu uživatelské přívětivosti by šlo mysqli_real_escape_string($pripojeni, trim($_GET['hledanytext'])); ale to je tak asi všechno.
Milan1236000
Profil
Keeehi:
Chtěl jsem právě jen zkusit co co dokáže. Ano, mysqli_real_escape_string($pripojeni, ($_GET['hledanytext'])) jsem tam měl původně, ale z důvodu, že ten vyhledávaný text i vypisuji do stránky a někdo by tam zadal třeba <a href="page.com">s</a>, tak na výstupu bude klikací odkaz, což bych nerad. Jako rozumný kompromis se mi zdál ten můj 1., nebo 2. skript.
Dan Charousek
Profil
Milan1236000:
Jak píše Keeehi, vše co potřebuješ je:
mysqli_real_escape_string($pripojeni, ($_GET['hledanytext']);

To o čem píšeš se ošetřuje až při výpisu z databáze.
Milan1236000
Profil
Keeehi, Dan Charousek:
Fajn, díky.
CZechBoY
Profil
[XSS]
Při vypisování textu vše escapuj podle toho kde to vypisuješ.
Např pokud to vypisuješ do html tak použij htmlspecialchars, pro css a js zase něco jiného.
Milan1236000
Profil
Ještě jsem narazil na jeden problém, který se tohoto tématu lehce dotýká.
Mám registrační formulář:
<?php if(isset($_POST['registrovat'])) $nick = htmlspecialchars(trim($_POST['nick'])); ?>
<form action="registrace.php" method="post">
  <label for="nick">Nick:</label><input type="text" id="nick" name="nick" value="<?php if(isset($nick)) echo $nick; else {echo ""; $chybi_nick=1;} ?>" placeholder="Zadej nick" maxlength="30"><?php if(isset($chybi_nick) && $chybi_nick==1 && !isset($_POST['registrovat'])) echo "<b style=\"color: red;\"> Zadejte nick</b>"; ?><br>
  <input type="submit" name="registrovat" value="Registrovat">
</form>
Problém je u podmínky, kdy se má zobrazil hláška "Zadejte nick". Schválně tam mám vykřičník, protože když ho smažu, tak se ta hláška nezobrazí nikdy, takhle se zobrazí jen dokud neodešlu formulář a po odeslání zmizí. Proč když ho smažu, tak se hláška nezobrazí jen když je pole prázdné a zároveň je formulář odeslán?
CZechBoY
Profil
Vykřičník znamená negaci podmínky - tzn. pokud není odeslaný formulář (nebo chybí odeslané políčko registrovat) tak je podmínka splněna (s vykřičníkem).

Doporučuju spíš validaci pomocí empty (prázdné/nenastavené pole) a trim (odebrané bílé znaky jak od začátku tak od konce):
if (empty($_POST['pole']) || trim($_POST['pole'] === '') { zobrazení chybové hlášky }
Keeehi
Profil
Když data neodešleš, podmínka na 1. řádku je false => proměnná $nick neexistuje => podmínka na třetím řádku je false => $chybi_nick se nastaví na jedna => první 2 částí druhého ifu na třetím řádku jsou splněny.

Ale je to zase celé takové nepěkné, zbytečně komplikované.
<?php $nick = !empty($_POST['nick']) ? trim($_POST['nick']) : '';

echo <<<HTML
<form action="registrace.php" method="post">
  <label for="nick">Nick:</label><input type="text" id="nick" name="nick" value="
HTML;
echo htmlspecialchars($nick, ENT_QUOTES);
echo <<<HTML
" placeholder="Zadej nick" maxlength="30">
HTML;

if(isset($_POST['registrovat']) && empty($nick)) {
  echo <<<HTML
<b style="color: red;"> Zadejte nick</b>
HTML;
}

echo <<<HTML
  <br>
  <input type="submit" name="registrovat" value="Registrovat">
</form>
HTML;
Milan1236000
Profil
CZechBoY, Keeehi:
Super, díky za inspiraci.
Milan1236000
Profil
Jako další bych potřeboval poradit ohledně email patternu. Zkoušel jsem následující skripty - oba fungují.
$email = htmlspecialchars(trim($_POST['email']));
if (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) $e="ok"; else $e="no";
a
$email = htmlspecialchars(trim($_POST['email']));
if(preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/",$email)) $e="ok"; else $e="no";

Je mezi nimi nějaký rozdíl (kdy který vyhodí nějakou chybu)? Jak by šel nejjednodušeji napsat ten druhý? Tento je zkopírovaný, ten zápis moc nechápu.
Keeehi
Profil
Pokud jsem to správně dohledal, FILTER_VALIDATE_EMAIL by měl fungovat stejně jako tento regex

/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD

Rozdíl tam určitě bude.

Milan1236000:
Jak by šel nejjednodušeji napsat ten druhý?
Není to vždy pravda ale většinou jednodušší (kratší) regulární výraz je obecnější, takže jím projdou u výrazy, které by v delším neprošly.


Obecně emailová adresa může mít opravdu obrovské množství tvarů a obrovské množsví jich mít zase nemůže. A je velmi obtížné napsat takový výraz, který by postihl všechny varianty. S čím se druhý regulár špatně potýká jsou třeba pomlčky v doméně. Email test@---.cz jím projde, přesto že doména ---.cz nemůže existovat.

A dále v ověřování tvaru emailu nevidím moc smysl. Jaký je tvůj důvod?
Milan1236000
Profil
Keeehi:
Teda, to je hustej filtr... :D
Šlo mi jen o správný tvar emailu, aby si tam nemohl každý psát, co chce. Nechám tam ten filtr a je to. Díky.
Keeehi
Profil
Milan1236000:
Šlo mi jen o správný tvar emailu, aby si tam nemohl každý psát, co chce.
Ale k čemu ti je, že tam napíše někdo něco co vypdá jako email. Přece když tam někdo napíše kughocnehgolsiuhlsieuhgcieuhgleriughlwirueg@wfzuggfaugflawgrfkwer.kggff tak to filterm projde ovšem pro tebe to má stejnou vypovídající hodnotu jako kdyby tam někdo napsal ščářž?&]˘°ł. Ani jeden ze vstupů není emailová adresa. Tedy ta první by mohla být ale to je vedlejší. Jediné ověření, které by tě mělo zajímat je tedy zda ten daný člověk zadanou emailovou adresu opravdu kntroluje, že má k ní přístup. A to se dá ověřit jedině zasláním emaiu na tu adresu s něčím tajným co pak bude následně po uživateli vyžadováno.
Milan1236000
Profil
Keeehi:
Ano, i ověření správnosti mě napadlo, zatím jsem však řešil jen tvar, nic víc.
Milan1236000
Profil
Pokud mám skript na ověření, zda zadaný uživatel v registračním formuláři již v databázi neexistuje a do pole napíšu byť jen jeden z těchto znaků: ě, č, ř (ostatní písmena s háčky jdou bez problému, akorát u těchto 3 je problém, mimochodem, proč zrovna tyto 3 zobrazují chybu?) zobrazí se chyba na posledním řádku:
$nick = htmlspecialchars(trim($_POST['nick']));
$vysledek_uzivatel_nick = $pripojeni->query("
SELECT    *
FROM    `uzivatele`
WHERE   Nick=\"$nick\"
");
$zaznam_uzivatel_nick = $vysledek_uzivatel_nick->fetch_object();
V php na začátku nastaveno SET NAMES utf8 mám. Jak by šlo ošetřit tohle?
Keeehi
Profil
Milan1236000:
Špatně escapuješ! Funkce htmlspecialchars se používá jen na ošetření dat, které chceš vypsat, ne dat, která obdržíš a už vůbec ne na data, která chceš poslat do databáze. Ty jí cpeš všude a to je špatně. Nevhodné použití ecapovacích funkcí může mít za následek snížení bezpečnosti místo jejího zvýšení. Správně by ten kód měl vypadat takto:

$nick = trim($_POST['nick']);
$vysledek_uzivatel_nick = $pripojeni->query("
SELECT *
FROM `maturitniprace_uzivatele`
WHERE Nick='".($pripojeni->real_escape_string($nick))."'");
$zaznam_uzivatel_nick = $vysledek_uzivatel_nick->fetch_object();

Pořádně si nastuduj phpfashion.com/escapovani-definitivni-prirucka a používej správné funkce ve správnou chvíli.
Milan1236000
Profil
Keeehi:
Díky za super článek, opravím.
Už to konečně jde, změnil jsem v mysql porovnávání na utf8_czech_ci. Předtím to bylo defaultně z neznámého důvodu na latin1_swedish_ci.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: