Portál AbcLinuxu, 1. května 2025 22:57
HTML design ©
Kamil Friš
2002
To je už 10 let, na tehdejší dobu docela normál... Byly daleko, daleko větší extrémy Neblika to, netroubi to, nezere to 100% CPU... U me dobry+1
1. Web 1.1 Úvod 1.1.1 Struktura složek 1.1.2 Názvy a přípony souborů 1.1.3 Typy souborů 1.2 Webhosting 1.2.1 Doména 1.2.2 WebhostingTohle je strukturované zjevně taky, ale struktura je totálně zatemněná a navigace tam není vůbec žádná. V libovolných papírových skriptech se dá obvykle vyznat líp, než v tomto. Přijde mi, že tohle udělal jeden patlač pro ostatní patlače, aby jim napsal, jak upatlat html stránku, ale není tam ani slovo o tom, že obvyklý web má nějaký účel a strukturu, a že u většiny webů, na jejichž vývoji se bude současný student později v praxi podílet, jde o to, aby tam zákazník našel rychle a bez dlouhého klikání vše, co potřebuje. To je věc, která autorovi zcela uniká.
$nazev=$_POST["nazev"]; ... //provedení kontroly dat $kontrola=true; if($nazev=="") {echo "<h2>Nebyl zadán název zboží</h2>\n"; $kontrola=false;} ... if($kontrola) { if(!$data=mysql_query("insert into zbozi (nazev,cena) values ('$nazev', $cena")) ...by měl být kdokoliv pověšen za něco (v tomto případě nejspíš palce od nohou) do průvanu - pokud by tam nebyla vůbec žádná kontrola, tak se dá říct "OK, je to jen příklad, není tam žádná kontrola", ale tohle, kde nějaká "kontrola" je, ale žádné oescapování, to je přímo žádost o SQL injektáž ...
a jednak je v phpku AFAIK zapnuté by default magic_quotes, takže ošetření vstupu dělá jazyk, proč s tím otravovat programátora?Hah. Pak se člověk diví, že kdejaký anonymous havijem vyhaxuje půlku webů v republice.
asi jako kdyby v půlce přednášky o mléčných výrobcích byla vložena informace, jak se pečou rohlíky, protože se na ně občas maže máslo ... o pečení rohlíků nechť se učí na hodině pekařství, a o tom, jak dětem na svačinu správně na rohlíky mazat máslo nechť se učí na rodinné výchověJenže tohle je kritická záležitost, která by se do lidí měla vtloukat zleva i zprava, stejně jako každý rodič dětem vysvětlí, že nemají žrát vše co najdou na silnici a s ohněm se nehraje, protože by se nemusel jen spálit, ale mohl by shořet i celý barák, včetně rodiny. Lepší kuchařská analogie by tedy byla, kdyby v půlce přednášky bylo uvedeno, že se nemá používat mouka infikovaná námelem, jinak to zabije stovky lidí, jako se to ve středověku čas od času stalo.
Jenže tohle je kritická záležitost, která by se do lidí měla vtloukat zleva i zprava,vo tom samozřejmě žádná, ale ...
stejně jako každý rodič dětem vysvětlí, že nemají žrát vše co najdou na silnicinevím, jestli jim to budu vysvětlovat při večeři
a s ohněm se nehraje, protože by se nemusel jen spálit, ale mohl by shořet i celý barák, včetně rodiny.a o tomhle nebudu mluvit při plavání, jen protože vodou se dá hasit a tedy je tam nějaká souvislost s ohněm ...
Lepší kuchařská analogie by tedy byla, kdyby v půlce přednášky bylo uvedeno, že se nemá používat mouka infikovaná námelem, jinak to zabije stovky lidí, jako se to ve středověku čas od času stalo.v půlce přednášky o mléčných výrobcích? - no, jak myslíš ...
Jedna věc je opomenout něco vysvětlit a jiná věc je, uvést špatný příklad.ok, a v čem konkrétně je to špatné, kromě toho, že to opomíná něco vysvětlit?
Při večeři sice nemusíš vysvětlovat, že se nemají jíst odpadky ze silnice, ale ten příklad PHP kódu výše je, asi jako kdybys před dětmi prohrabal sousedovu popelnici, něco z ní vytáhl a šel z toho uvařit večeři a pak jste si na tom pochutnali. Jistě, za určitých okolností to může být jedlé (program použitelný), ale z didaktického hlediska stejně naprosto nevhodné.se mi zdá, že ti tato analogie tak trošku nefunguje ...
$nazev=$_POST["nazev"]; … //provedení kontroly dat $kontrola=true; if($nazev=="") {echo "<h2>Nebyl zadán název zboží</h2>\n"; $kontrola=false;} … if($kontrola) { if(!$data=mysql_query("insert into zbozi (nazev,cena) values ('$nazev', $cena")) …Opomenuté vysvětlení „nepodstatného detailu“ by bylo, kdybys vůbec nepracoval s
$_POST[]
a místo toho to zabalil do nějaké metody, a u jejího parametru by bylo napsáno, že smí obsahovat jen bezpečné znaky (např. a-zA-Z0-9) – pak bychom možná mohli opomenout, jak ty bezpečné znaky získat, když na vstupu od uživatele budou i nebezpečné.
Ale stejně by to byl špatný příklad, protože za escapování těch znaků by se mělo dělat těsně před vložením do SQL příkazu – jinak se na to může zapomenout.
A hlavně: programátor vůbec nemusí nic ručně escapovat a může to za něj udělat databázová vrstva jako PDO – použití parametrizovaných dotazů je správná cesta a dokonce ani není pracnější, než tohle lepení SQL z kousků textu.
Opomenuté vysvětlení „nepodstatného detailu“ by bylo, ...hele víš co, jdi do háje, nemám náladu na diskusi tímto stylem - nikdo neřekl, že je to "nepodstatný detail"
nikdo neřekl, že je to "nepodstatný detail"No, řekl bych že ta učitelka to vyjádřila víc než jasně :)
Bezpečnost je stejně tak součást programování, jako třeba výkon (neplýtvání případně optimalizace) nebo správnost (aby program odpovídal zadání).... mně by jenom zajímalo, kolik ses toho učil o optimalizacích a správnosti na první hodině programování, a jestli tohle všechno řešíš pokaždé, když někomu ukazuješ nějakých pár triviálních proof-of-concept příkazů ...
a jednak je v phpku AFAIK zapnuté by default magic_quotes, takže ošetření vstupu dělá jazyk, proč s tím otravovat programátora?This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0. A pokud vím, už dlouho nejsou zapnuté by default (od PHP 5.0 určitě). Navíc to je hrozný zdroj problémů, kdy aplikace obvykle musí napřed napravit škody, které tahle blbost napáchala. Správný přístup reprezentuje například PDO, kdy se zadávají do SQL dotazu značky (proměnné), jejichž hodnoty jsou určeny v samostatných argumentech. Tím se programátorovi ušetří starosti a zvýší se bezpečnost (tedy oproti magic_quotes se bezpečnost zavede).
zaměstnanec eshopu nebo co to má být za příklad napáchá dost škody už jen samotným zadáním špatné ceny, na to nepotřebuje SQL injection, takže asi má jistou důvěru, že se jako uživatel tohoto rozhraní nebude o SQL injection pokoušetSQL injection může vést např. k tomu, že brigádník, který měl původně jen vkládat fotky nebo popisky zboží, bude najednou mít možnost označit nějakou objednávku jako zaplacenou a nechat si poslat zboží zadarmo (nebo si nastavit slevu 90%, na což by se ani nemuselo přijít).
a jednak je v phpku AFAIK zapnuté by default magic_quotes,magic_quotes je prasárna a v PHP 5.3 je zavržená a v 5.4 odstraněná.
takže ošetření vstupu dělá jazyk, proč s tím otravovat programátora?Chybná je už ta úvaha, že ošetřujeme vstup. Naopak, je potřeba ošetřovat výstup – mj. proto, že výstupy můžou být různé –- jednou do XHTML na webu, jindy do LaTeXu pro tisk faktur, jindy do e-mailu, kde stejné znaky zakóduješ zase jinak…
stále mi nějak uniká, jak se to principielně liší od případu, kdy nastaví cenu zboží 0 (a nechá si ho poslat), což v daném příkladu může(*) i bez SQL injection? (*) a nevymýšlej si prosím virtuálního brigádníka, který "jen vkládá fotky nebo popisky" když v onom příkladu se jasně manipuluje s názvem a cenouzaměstnanec eshopu nebo co to má být za příklad napáchá dost škody už jen samotným zadáním špatné ceny, na to nepotřebuje SQL injection, takže asi má jistou důvěru, že se jako uživatel tohoto rozhraní nebude o SQL injection pokoušetSQL injection může vést např. k tomu, že brigádník, který měl původně jen vkládat fotky nebo popisky zboží, bude najednou mít možnost označit nějakou objednávku jako zaplacenou a nechat si poslat zboží zadarmo (nebo si nastavit slevu 90%, na což by se ani nemuselo přijít).
Chybná je už ta úvaha, že ošetřujeme vstup. Naopak, je potřeba ošetřovat výstup – mj. proto, že výstupy můžou být různé –- jednou do XHTML na webu, jindy do LaTeXu pro tisk faktur, jindy do e-mailu, kde stejné znaky zakóduješ zase jinak…hm, zajímavé, tvůj náhled na zpracování dat zcela popírá vše, co jsem se kdy učil ... takže tvoje představa je, že program zblajzne na vstupu cokoliv, dělá si s tím co chce, a pak, pokud mezitím nesegfaultuje kvůli nekompatibilitě datových typů apod., to předá nějakému magickému výstupnímu filtru, který zkonzultuje křišťálovou kouli a v případě výstupu v SQL rozhodne, jestli to co dostal je pokračování předchozí části složeného dotazu anebo pokus o SQL injection anebo šum, který náhodou vyšel syntakticky správně ...? no, mě učili, že když dostanu na vstupu data, tak si mám zkontrolovat, zda je to to, co očekávám (tedy například jaká mám pravidla na jméno zboží, že nepřipouštím název Little Bobby Tables), a teprv potom s tím pracovat, přičemž už vím (samozřejmě pokud jsem v programu neudělal chybu), co předávám tomu výstupnímu filtru (který bere čistá data a sám k nim přidává onu potřebnou omáčku pro různé formáty), a ten tudíž nepotřebuje onu křišťálovou kouli, aby věděl, jak s tím pracovat
stále mi nějak uniká, jak se to principielně liší od případu, kdy nastaví cenu zboží 0 (a nechá si ho poslat), což v daném příkladu může(*) i bez SQL injection?Příklady obvykle popisují jen část problému – představ si, že na tom příkladu bude student stavět a bude chtít nedejbože vyrobit skutečný elektronický obchod – přidá tam pár IFů, aby rozlišil, kdo je zákazník, kdo brigádník a kro správce, který může všechno. A určité akce umožní dělat jen určitým rolím. A myslí si, že to hezky zabezpečil. Jenže ho nikdo nenaučil, že mazaně formulovaný uživatelský vstup může narušit SQL dotaz a nejen narušit, ale i spustit vlastní příkazy. Podle nějakých statistik jsou SQL injekce stále jedním z největších bezpečnostních problémů na webu. Sice se mi to nezdálo a říkal jsem si, že po tolika letech a tolika bezpečnostních incidentech by se lidi konečně mohli naučit používat parametrizované dotazy… ale asi ne – a takovéhle příklady tomu nahrávají.
takže tvoje představa je, že program zblajzne na vstupu cokolivJe potřeba rozlišovat dvě roviny: syntaktickou a sémantickou. Sémantické kontroly dávají samozřejmě smysl už na vstupu – např. když zadáváme věk, mělo by to být kladné číslo ne větší než třeba 256. Syntaxi naopak zkontrolovat nemůžeme, protože předem nemůžeš bezpečně vědět, kudy programem data potečou a na jaké výstupy se dostanou – pokud může být vstupem textový řetězec, tak neřeš, jestli obsahuje ', " &, <, \ atd. nemá to cenu, protože nedokážeš vybalancovat bezpečnost (pro potenciálně libovolný výstupní formát – v každém budou jiné zvláštní znaky) a použitelnost (uživatelé chtějí zadávat jména s ' nebo názvy firem s &). A řeš to až na konkrétním výstupu a do té doby s tím pracuj jako s libovolným textovým řetězcem.
to předá nějakému magickému výstupnímu filtru, který zkonzultuje křišťálovou kouli a v případě výstupu v SQL rozhodne, jestli to co dostal je pokračování předchozí části složeného dotazu anebo pokus o SQL injection anebo šum, který náhodou vyšel syntakticky správně ...?Křišťálová koule právě není potřeba. Musíš mít pouze jasno v tom, co jsou data (parametry) a co je kód (zde SQL příkaz) a nikdy se ti to nesmí pomíchat. Kód je buď přímo součástí programu nebo se načítá z nějakých konfiguráků, za jejichž správnost ručíš. Datům naopak věřit nemůžeš a musíš je escapovat – a to tím způsobem, jaký vyžaduje daný výstup (jinak budeme escapovat pro SQL jinak pro XHTML atd.) resp. to escapování za tebe udělá nějaká mezivrstva, nemusíš si to psát sám. V principu nějak takhle:
vykonejSQL("INSERT INTO tabulka (sloupeček_1, sloupeček_2) VALUES (?, ?);", array($_POST["parametr_1"], $_POST["parametr_2"]));tzn. není potřeba nic věštit a data jsou od kódu jednoznačně oddělena a nikdy se nestane, že by se data interpretovala jako kód.
tedy například jaká mám pravidla na jméno zboží, že nepřipouštím název Little Bobby TablesTo je špatně, protože třeba takový řetězec obsahující apostrofy je legitimním názvem zboží, stejně tak se někdo může jmenovat třeba M'Gregor – je potřeba to escapovat, protože jinak mu buď zprzníš jméno (naprosto zbytečné) nebo si rozbiješ SQL dotaz (potenciálně nebezpečné a nepříjemné, protože člověk s takovým jménem se nebude moci registrovat v tvém systému). Viděl jsem např. systém, který padal, když si uživatel chtěl do popisu určité entity zadat „aaa <-> bbb“ – chtěl tím naznačit šipku a poznamenat si vazbu mezi aaa a bbb – uživatel má právo zadávat takové popisy – chyba byla v programu, protože ta data chtěl interpretovat jako XML fragment, což vyvolalo výjimku. Řešením bylo, zacházet s těmi daty jako s prostým textem a escapovat ho na výstupu (XHTML, LDAP, SQL – pokaždé jinak).
fajn, a to na moji námitku, které řeší důvěru v onoho "brigádníka", odpovídá jak?stále mi nějak uniká, jak se to principielně liší od případu, kdy nastaví cenu zboží 0 (a nechá si ho poslat), což v daném příkladu může(*) i bez SQL injection?Příklady obvykle popisují jen část problému –
... představ si, že na tom příkladu bude student stavět a bude chtít nedejbože vyrobit skutečný elektronický obchod – přidá tam pár IFů, aby rozlišil, kdo je zákazník, kdo brigádník a kro správce, který může všechno. A určité akce umožní dělat jen určitým rolím. A myslí si, že to hezky zabezpečil. Jenže ho nikdo nenaučil, že mazaně formulovaný uživatelský vstup může narušit SQL dotaz a nejen narušit, ale i spustit vlastní příkazy.nechápu, proč si mám představovat takové nesmysly normální student bude ve studiu pokračovat a naučí se příklady, jak to zabezpečit stále nerozumím, proč chceš po učitelce v první třídě, nebo kde se učí, že 1 + 1 jsou dvě, aby vysvětlovala, že i2 + i2 jsou mínus dvě
Sémantické kontroly dávají samozřejmě smysl už na vstupu – např. když zadáváme věk, mělo by to být kladné číslo ne větší než třeba 256.vs
jo ahatedy například jaká mám pravidla na jméno zboží, že nepřipouštím název Little Bobby TablesTo je špatně, ...
Křišťálová koule právě není potřeba. Musíš mít pouze jasno v tom, co jsou data (parametry) a co je kód (zde SQL příkaz) a nikdy se ti to nesmí pomíchat.a říkám něco jiného?
V principu nějak takhle:parametr_1="1,1); DROP TABLE ..." jo ahavykonejSQL("INSERT INTO tabulka (sloupeček_1, sloupeček_2) VALUES (?, ?);", array($_POST["parametr_1"], $_POST["parametr_2"]));tzn. není potřeba nic věštit a data jsou od kódu jednoznačně oddělena a nikdy se nestane, že by se data interpretovala jako kód.
... Řešením bylo, zacházet s těmi daty jako s prostým textem a escapovat ho na výstupu (XHTML, LDAP, SQL – pokaždé jinak).no, pak jsme si asi nerozuměli ještě jednou: ... přičemž už vím (samozřejmě pokud jsem v programu neudělal chybu), co předávám tomu výstupnímu filtru (který bere čistá data a sám k nim přidává onu potřebnou omáčku pro různé formáty) domníval jsem se, že mluvíš o konstrukci celého výstupního řetězce
fajn, a to na moji námitku, které řeší důvěru v onoho "brigádníka", odpovídá jak?Příklad (špatně) vysvětluje část problému zvanou „práce s databází“, zatímco část věnující se návrhu a tomu, že uživatelé můžou mít různé role a role různá práva, přeskakuje – to by bylo v pořádku, tu druhou část si může člověk dostudovat později, ale ta první část by měla být vysvětlena pořádně resp. bez chyb – jinak budou ti studenti stavět na chatrných základech a jejich systémy budou děravé…
nechápu, proč si mám představovat takové nesmysly…budou si myslet, že už umí pracovat s databází a vrhnou se na studium něčeho jiného – aby mohli co nejdříve postavit kompletní aplikaci – ale kvůli těm mizerným základům se to celé zhroutí. Asi jako kdyby se zedník ještě nenaučil stavět pevné zdi, ale už se vrhnul na střechu, spotřeboval na to spoustu dřeva a tašek a nakonec mu to celé spadlo. To je škoda, ne?
normální student bude ve studiu pokračovat a naučí se příklady, jak to zabezpečitBezpečnost by neměla vypadat tak, že to uděláme blbě a pak se to snažíme nějak „zabezpečit“ – dodatečně tam můžeš dodělávat věci typu IDS/IPS, ochrana proti DoSu, ale aplikace jako taková by měla být bezpečná už od začátku.
jo ahaVěk člověka si celkem snadno definujeme jako kladné číslo v určitém rozsahu a limitování těch hodnot neděláme kvůli bezpečnosti SQL dotazů, ale spíš jako ochranu proti překlepům – pokud někdo zadá „23,“, tak je jasné, že tam tu čárku má omylem a je potřeba to opravit, stejně jako když někdo napíše „padesát“, to by nám v systému dělalo bordel, protože bychom to nemohli strojově zpracovat, takže takové hodnoty zakážeme (znovu opakuji: neděláme to kvůli zabezpečení). Oproti tomu název nějaké entity (osoby, firmy, spolku atd.) lze jen těžko nějak blíže specifikovat, a tak je lepší povolit obecně jakýkoli řetězec – klub francouzštinářů si tam nacpe francouzské znaky, webařská firma si tam dá ostré závorky, jiná firma si tam dá &, klub hackerů bude mít v názvu apostrofy a středníky… nemá cenu to řešit – prostě libovolný textový řetězec, maximálně omezíme délku a je to. Jiné omezování vede akorát k tomu, že části uživatelů způsobíš problémy a bezpečné to stejně nebude, protože určitě na něco zapomeneš – vybalancovat se to nedá. (a i kdybys nějaké filtrování nastavil, stejně se nesmíš vykašlat na escapování pro daný výstupní formát).
a říkám něco jiného?Vzhledem k tomu, jak se tu zastáváš lepení SQL dotazů z kousků textu (byť údajně prohnaných nějakým filtrem), tak mi přijde že ano – data a kód v takovém případě splývají.
parametr_1="1,1); DROP TABLE ..." jo ahaDostuduj si, jak fungují parametrizované SQL dotazy (ať už v Javě, PHP, kdekoli, princip je stejný). Díky nim takový útok není možný.
přičemž už vím (samozřejmě pokud jsem v programu neudělal chybu), co předávám tomu výstupnímu filtru (který bere čistá data a sám k nim přidává onu potřebnou omáčku pro různé formáty)Co jsou to „čistá data“? Jak v této formě bude vypadat třeba firma „Truhlář & syn“? Nebo „Hell's Kitchen“? Nebo třeba „Hackers \Contest 2012“? První ti rozbije XHTML/XML, druhé ti nepůjde vložit do databáze a třetí ti rozbije dokument v LaTeXu. Pokud to ošetříš s ohledem na jeden výstup, rozbiješ to ve dvou zbývajících. Pokud zakážeš vše kromě [A-Za-U0-9], tak se to snad nerozbije, ale nebudeš plnit uživatelské požadavky, protože uživatelé chtějí zadat skutečný název firmy nebo své akce, nikoli zkomolený. I kdyby na to byli ochotní přistoupit, je zbytečné takhle degradovat software jen kvůli vlastní neschopnosti. P.S. Reálné příklady z praxe: e-mailový systém, že kterého chodí nesmyslné paznaky v předmětech zpráv, protože ty matláky nenapadlo, že když zvláštní znaky na vstupu escapují pro HTML, nebude to v e-mailových hlavičkách* fungovat, protože tam se ty znaky kódují jinak. Nebo děravé diskusní fórum, protože kodér si myslel, že je lepší filtrovat než escapovat. *) a v těle zprávy jim to funguje jen shodou náhod, protože to posílají taky v HTML
SQL injection může vést např. k tomu, že brigádník, který měl původně jen vkládat fotky nebo popisky zboží, bude najednou mít možnost označit nějakou objednávku jako zaplacenou a nechat si poslat zboží zadarmo (nebo si nastavit slevu 90%, na což by se ani nemuselo přijít).No, tj docela lame. Chytřejší brigádník dumpne databázi, emaily a hesla uživatelů otestuje vůči smtp, funkční accounty pak prodá na TORu. Na číslech kreditek se napakuje sám, případně je taky prodá, i když by na tom prodělal.
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.