Portál AbcLinuxu, 12. května 2025 06:37
<?php $_POST['name'] = htmlspecialchars($_POST['name']); $_POST['last'] = htmlspecialchars($_POST['last']); $_POST['pass'] = htmlspecialchars($_POST['pass']); $query = "INSERT INTO `registrace` (`name`, `last`, `pass`, `datum`, `status`) VALUE ('".mysql_real_escape_string($_POST['name'])."', '".mysql_real_escape_string($_POST['last'])."', '".mysql_real_escape_string($_POST['pass'])."', NOW(), ".intval(0).")"; ?>
Řešení dotazu:
$_POST['name'] = htmlspecialchars($_POST['name'], 'UTF-8'); $_POST['last'] = htmlspecialchars($_POST['last'], 'UTF-8'); $_POST['pass'] = htmlspecialchars($_POST['pass'], 'UTF-8');
htmlspecialchars($nazev ,none, 'UTF-8');
mysql_real_escape_string
, například zda používá syntaxi, která do posledního puntíku odpovídá parseru MySQL, kterou právě používáte. Já bych na to nespoléhal, a raději bych použil parametrizovaný dotaz, který je bezpečnější, podle mne přehlednější a snáze se používá, a ještě umožní dělat lepší optimalizace (prostě samá pozitiva a sociální jistoty).
$stmt = $dbh->prepare("INSERT INTO `registrace` (`name`, `last`, `pass`, `datum`, `status`) VALUES (?, ?, ?, now(), 0)"); if ($stmt->execute(array($_POST['name'], $_POST['last'], $_POST['pass']))) { … }
htmlspecialchars()
bych si nechal až na případný výstup, zvlášť u toho hesla je to spíš chyba – když uživatel zadá heslo „I<3you“, asi bude při přihlašování psát také „I<3you“ a ne „I<3you“.
$pdh
jsem předpokládal objekt připojení k databázi, třeba výsledek volání
$dbh = new PDO('mysql:host=localhost;dbname=db', 'user', 'pwd');Podívejte se na dokumentaci PHP Data Objects.
htmlspecialchars()
. Ale ve výsledku je to tady zbytečné používat samozřejmě.
htmlspecialchars()
není na místě. Prostě jsem se soustředil pouze na to, říct, jestli je to v pohodě ošetřený a neřešil jsem, jestli je na místě použít zrovna tuto escapovací proměnou.
$query = "INSERT INTO `registrace` (`name`, `last`, `pass`, `datum`, `status`) VALUES ('".mysql_real_escape_string($_POST['name'])."', '".mysql_real_escape_string($_POST['last'])."', '".mysql_real_escape_string($_POST['pass'])."', NOW(),0);";Ovšem parametrizovaný dotaz by vypadal mnohem lépe a bezpečněji.
mysql_real_escape_string()
a jinými funkcemi závislými na použité databázi.
Smazání databáze přes formulář jsem viděl v reálu a není to ani moc složité. Ovšem popisovat to nebudu, protože díky systematickému používání parametrizovaných dotazů mě to už přestalo zajímat.
Hrozeb je samozřejmě víc. Stačí, když se někomu v důsledku chyby v aplikaci vytratí z SQL dotazu při mazání záznamu WHERE i s podmínkou apod.
jak může někdo pomocí formuláře smazat mysqlTakhle: Maminčiny exploity
name
text "Pepa", je to něco, s čím počítáte a z čeho vznikne následující dotaz:
INSERT INTO `registrace` (`name`, `last`, `pass`, `datum`, `status`) VALUE ('Pepa', 'Novák', 'neřeknu', NOW(), 0)Taky vám tam ale může vyplnit tohle:
', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; --A pak dostanete (bez escapování) tenhle příkaz:
INSERT INTO `registrace` (`name`, `last`, `pass`, `datum`, `status`) VALUE ('Pepa', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; -- ', 'Novák', 'neřeknu', NOW(), 0)Záleží pak na tom, co dělá escapovací funkce -- ale pokud se přes ni podaří protlačit data, aby dala takovýhle výsledek, provede se dotaz úplně stejně. Ta escapovací funkce je přitom závislá na spoustě věcí -- verze MySQL databáze, kódování vstupu a výstupu atd. Těžko to bude ve všech kombinacích fungovat správně jen tak bez nějakého dalšího nastavování. Takže náhodný kolemjdoucí, který jen zkusí zadat jednu variantu textu do formuláře, vám databázi asi nesmaže, ale pokud bude mít někdo motivaci, zjistí si verzi databáze, PHP, kódování vstupů a výstupů, má už mnohem větší šanci na úspěch.
User vyplnil text Pepa formulář bude tedy vypad takto <input type="text name="name" value="Pepa" /"> a v php dostanu tohle echo $_POST['name']; // Pepaale taky to může být takto
User vyplnil text ', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; -- formulář bude tedy vypad takto <input type="text name="name" value="', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; -- " /"> a v php dostanu tohle echo $_POST['name']; // ', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; --Pochopil jsem to správně? Jestli ano tak k tomu mám dvě věci (z pohledu lajka)
1) znaky ',()0;- nemají ve jménu co dělat //lenost programátora 2) aby tohle uhodl, musel by být kouzelníkPokud to tedy shrnu, tak pokud programátor ošetří třeba pomocí reg. výrazu input name jake znaky může user použít, tak nemusí již dál nic řešit, jelikož útočník nemá sebemenší šanci se nějak nabourat. Ale třeba se mi snažíte říct něco úplně jiného a já to nepochopil. Děkuji
znaky ',()0;- nemají ve jménu co dělat //lenost programátoraTohle je až druhotný problém. V první řadě nesmíš dovolit, aby se vstup od uživatele vykonával jako SQL dotaz – smí být pouze parametrem dotazu, který jsi napsal a zkontroloval ty. Tohle je základ. Jestli kontrolovat povolené znaky a dělat nějaká další omezení, to je věc druhá – nicméně to se nedělá (nemělo by) kvůli bezpečnosti (tu zajistíš viz výše), ale kvůli nějakému většímu pořádku v datech – např. zakážeš mezery, aby uživatel nenacpal jméno a příjmení do jednoho políčka a správně je rozepsal do dvou. Taky můžeš omezit znaky na A-Ž. Jenže pak ti tam přijde člověk např. s francouzským jménem a tam jsou i jiné znaky, takže se nebude moci registrovat. A podobné zbytečné problémy, na které sis sám zadělal. Tahle omezení doporučuji stanovovat s rozvahou a nestavět na nich bezpečnost – ta by měla stát na těch parametrizovaných dotazech. A další věc je výstup aplikace – v případě webové je to (X)HTML – tam je potřeba zase ošetřit znaky, aby útočník do tvé aplikace nevložil např. svoje JavaSkripty. Sice když omezíš znaky ve jméně na A-Ž, tak tam skript nevloží, ale je to špatné řešení – spolehlivé je všechny výstupy escapovat – buď ručně voláním funkce nebo použít nějaký šablonovací nástroj. To je spolehlivé a opět je ti jedno, že někdo do jména zadal jakkoli nesmyslné znaky – stránku ti to nenaruší a ostatní uživatele neohrozí.
aby tohle uhodl, musel by být kouzelníkNajdi si něco o „SQL injection“ – skutečně to takhle chodí a útočník nemusí být kouzelník – hodně věcí je předvídatelných a zbytek se dá dohledat postupným zkoušením – když někdo takhle zprasí aplikaci, tak často taky neskrývá chybové hlášky, tzn. zobrazí se chybová hláška, kterou vyplivla SQL databáze – a z ní útočník získá další zajímavé informace. Pak je tu schéma, ze kterého zjistí názvy tabulek a sloupečků atd.
znaky ',()0;- nemají ve jménu co dělat //lenost programátoraNojo, ale vždyť vy to tam nikde ošetřené nemáte.
aby tohle uhodl, musel by být kouzelníkNemusel. MySQL při některých nastaveních zkonvertuje kdeco do kdejakého sloupečku, spousta sloupců může mít povolenu hodnotu NULL, mají výchozí hodnoty -- takže může stačit uhodnout počet sloupců, což je na pár pokusů. Zvlášť když budete chybové zprávy vypisovat do stránky.
formulář bude tedy vypad taktoFormulář tak rozhodně vypadat nebude. To je jen naivní představa některých vývojářů. Možná to tak prezentuje nějaký debugger.<input type="text name="name" value="', 'Novák', 'neřeknu', NOW(), 0); DROP DATABASE; -- " /">
1) znaky ',()0;-
nemají ve jménu co dělat //lenost programátora
To bych chtěl vidět, jak to chceš ošetřovat. Proč by někdo nemohl mít v nickname "0"? Které z několika desítek tisíc znaků jsou podle tebe závadné? Rozhodně jsi všechny nevyjmenoval.
2) aby tohle uhodl, musel by být kouzelníkTakového "kouzelníka" jsem viděl při akci. Ani nebyl moc znalý ani šikovný, ale v druhém panelu si otevřel nějakou stránku s nápovědou a bylo to.
Pokud to tedy shrnu, tak pokud programátor ošetří třeba pomocí reg. výrazu input name jake znaky může user použít, tak nemusí již dál nic řešit, jelikož útočník nemá sebemenší šanci se nějak nabourat.Tak takový regulární výraz bych chtěl vidět. Navíc tím poškodíš i to, co poškodit nesmíš. Například velmi často se ve jméně vyskytuje apostrof. Když to změníš, tak si někdo může stěžovat. Nebo snad chceš dotyčnému vystavit občanku s backslashem před apostrofem ve jméně? Také jsem si nechal jedno "nedobytné" fórum rozbít od jednoho testera. Povedlo se mu to 3x, počtvrté už ne. Ovšem stále jsem neměl plnou jistotu, že mám ošetřeno všechno. Těch znaků, které mi to fórum úspěšně demolovaly, bylo mnohem víc, než zmíněné
',()0;-
.
Nakonec neošetřuji žádné a tester to vzdal. Stačilo použít parametrizované dotazy a už si neškrtl. Kód programu se zkrátil a zjednodušil. Co víc si přát?
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.