Nine Things to Expect from HTTP/2 bod 7:
That’s because textual protocols have to cover issues like how to delimit strings (counted? double-newline?), how to handle whitespace, extra characters, and so on. This leads to a lot of implementation complexity; in HTTP/1, there are no fewer than three ways to tell when a message ends, along with a complex set of rules to determine which method is in use.
HTTP/1’s textual nature has also been the source of a number of security issues; because different implementations make different decisions about how to parse a message, malicious parties can wiggle their way in (e.g., with the response splitting attack).
Nevím jak Vám, ale mně to zní jako docela rozumné argumenty.
Mno a do binarniho streamu se prozmenu da vlozit kus spustitelnyho kodu, kterej si pak prohlizec klidne spusti, trebas diky nejaky uzasny ficure ktera zavola exec. To se do textu dela dost blbe, treba prave kvulu vsemoznym uvozovkam, ktere se v te binarce jaksi neresej.
Mimochodem, nefunguje presne takhle vecne deravej flash?
Tak třeba tady je popsána díra, http://www.root.cz/clanky/dira-v-bashi-ktere-si-20-let-nikdo-nevsiml/ která se dá využít i přes textový formát hlaviček a binární hlavičky by na její využitelnosti nic nezměnily.
Takže tvrdím, že binární/textový formát výrazně bezpečnost neovlivní. Textová reprezentace odpudí maximálně 1% útočníků, kteří se nechtějí učit, jak escapovat kód a jsou líní si to i vygooglovat :-)
Nutno dodat, že binární reprezentace stejný díl útočníků odradí, protože se nechtějí učit jak kód zakódovat aby byl spuštěn (ostatně donuťte třeba prohlížeč obrázků aby spustitelný kód vložený do jpegu spustil (příklad binárního formátu). Většinou je potřeba zjistit kde mu šlápnout na kuří oko, třeba nějakým vhodným buffer overflow), a jsou líní si to vygooglovat.
1) obrazky spustit lze (obzvlast v systemu ktery netreba jmenovat)
2) od obrazku se prevazne neceka nic jinyho, nez jeho zobrazeni => v nejjednodussim pripade se veme sada bajtu a natlaci se do graficky pameti.
Kdezto web musi delat spoustu ruznych veci a spousta toho co je uvnitr slouzi jako parametr hromady funkci. A vzhledem k tomu, ze dneska si s kontrolou vstupu nikdo hlavu nelame, tak v okamziku, kdy ten vstup bude binarni ...
Nechci vám tady kazit vaše rozsáhlé teorie založené na rozsáhlých neznalostech, ale HTTP je pouze přenosový protokol, který binární obsah umí přenášet odjakživa. A web nemusí být přenášen jenom protokolem HTTP, webovou stránku si klidně můžete stáhnout přes FTP, poslat e-mailem, nebo ji mít jako soubory na disku. Tam všude také mohou být binární data. Takže to, že se na webu pracuje s binárními daty, platí už asi tak 25 let. Naštěstí to nijak nevadí, protože parametry funkcí opravdu nejsou binární a nebinární, ale mají různé datové typy - třeba char, integer, pointer nebo v objektových jazycích typicky pointer na určitý objektový typ. No a hlavně ty funkce zpravidla dělají něco jiného, než že by své parametry spouštěly jako spustitelný kód.
HTTP dtto.
Poslyšte, pokaždé, když uvedete svůj komentář „blb jako XY“, usvědčí vás ostatní z toho, že o dané věci nevíte vůbec nic. S DNSSEC jste se tady takhle ztrapnil pro jistotu dvakrát, v této diskusi jste předvedl, že nevíte nic o kešování v prohlížečích, teď že vůbec nechápete, co je to binární protokol a jak se vůbec webové stránky v prohlížečích zpracovávají. Když už jste tedy dosáhl toho, že jste tu všeobecně považován za blba, nestálo by za to opustit svou ničím nepodloženou aroganci, a začít se chovat velice slušně, abyste se alespoň něco dozvěděl?
Ano, to jste přesně popsal důvod, proč je HTTP/2 binární protokol, protože pokud nadefinujete formát, který je binární, tak nenechává prostor pro vlastní kreativitu.
Nejasnost v \r\n vs \n vs ... budete mít v textovém formátu vždy, protože vám budou lidi řvát, že to zrovna jejich oblíbeným telnetem nejde udělat...
Obecně je formát, který není potřeba parsovat kvůli delimiterům (ať už to jsou djb netstrings, Google protobuf nebo cokoli jiného, kde není potřeba hledat ve stringu CRLF) lepší pro síťový přenos dat, kterým nelze věřit.
Do binárního formátu pak jde taky přidat komprese... a dá se využít celá bitová šířka přenosu (jen si vemte, jak moc je neefektivní base64).
Vlastní kreativita se nechá aplikovat kdykoliv a jakkoliv.
Nejasnost mezi \r\n vs \n je v pohodě, pokud se zakáže \r a případné jeho výskyty se budou ignorovat.
Jakýkoliv formát, který je potřeba zpracovávat, je problematický, protože to zpracování je největší slabinou. Protože nikdo nikdy nikomu nezabrání napsat parser, který parsuje něco trochu jinak, a pokud se to stane součástí oblíbeného zařízení či programu, jiná varianta standardu je na světě.
Přiznám se, že nevidím moc rozdílů mezi hledáním oddělovačů a počítáním přírůstků, o kolik se má posunout ukazatel.
> Nejasnost mezi \r\n vs \n je v pohodě, pokud se zakáže \r a případné jeho výskyty se budou ignorovat.
První bugreport "Mně z toho leze jeden dlouhý řádek, to je protokol na ..." za 3 2 1.
> Jakýkoliv formát, který je potřeba zpracovávat, je problematický, protože to zpracování je největší slabinou.
MUHEHEHE
Bez zpracování se jakákoliv data dají poslat tak do /dev/null. Pokud se mají k něčemu použít, tak se musí co?
Mě ten bod přijde trochu pochybný. Implementaci HTTP/2 budou podle mě dělat primárně 3 hlavní prohlížeče (FF,Crome,IE), 3 hlavní servery (apache,nginx,iss) a pár síťových knihoven a tam je určitě parsování napsáno dobře.
Pro ostatní aplikace - když si někdo zbastlí např. na jednočipu primitivní server nebo aplikaci na stahování dat ze serverů (a dělá chyby v parsování) - tak tam není moc smysl přidávat další složitosti a jít na http/2 - výkonový přínos bude pravděpodobně zanedbatelný (pokud to nebude na nějaké hodně pomalé lince).
Mně jako nejrozumnější část bodu 7 připadá poslední odstavec: "Of course, all of this is small solace for the poor ops person who just wants to debug the protocol. That means that we’ll need new tools and plenty of them to address this shortcoming; to start, Wireshark already has a plug-in." Ty ostatní argumenty jsou pro rozhodování mezi textovým a binárním protokolem irelevantní.
Implementační složitost binární obálky v HTTP/2 daleko je mnohem vyšší, než ošetření konců řádků, whitespace, apod. v HTTP/1. Délka zprávy je určená na základě kombinace hlavičky content-length a součtem délek DATA frames, proti HTTP/1 s Content-Length a Transfer-Encoding: chunked to není až takový rozdíl.
Spousta problémů s textovou reprezentací je způsobena nikoliv protokolem, ale používáním řetězcové knihovny jazyka C. Po dekódováná stejně dostaneme hodnoty hlaviček jako text, který se bude dál zpracovávat.
Záleží na konkrétním protokolu. V případě HTTP/1.1 a HTTP/2 jsem o tom přesvědčen. Oba protokoly jsou do značné míry stejné, HTTP/2 má navíc binární obálku. Místo jednoduchého parsování posloupnosti řádků "Jméno: hodnota" je potřeba řešit kompresi a dekompresi hlaviček (specifikace má 57 stran). Nakonec z toho stejně vypadnou textové hodnoty jednotlivých hlaviček, a ty je potřeba dál zpracovat.
K tomu si přidejte, že je rozdíl mezi tím, co říká specifikace, a tím, co po síti skutečně chodí. Textový formát má redundanci, která často umožní pochopit, co tím odesílatel vlastně myslel, a nějak rozumně to zpracovat. Když místo nestandardního textu přijde nestandardní binární smetí, tak je mnohem těžší se s tím vypořádat.
Jak často se to stává, že chodí nějaké nestandardní binární smetí? Podle mne se nanejvýš stane, že nějaká položka je mimo vyjmenované hodnoty (typicky "pro budoucí použití, musí být nula" a přijde nenulová hodnota), ale tím nemůže rozhodit parsování zbytku zprávy. Navíc ta heuristika, která pochopí, co tím odesílatel vlastně myslel, musí být součástí kódu. A každý si ji udělá trochu jinak, pak někdo naprogramuje kód jen tak od oka ("vždyť je to jednoduchý textový protokol, to nemusím číst specifikaci"), proti jedné implementaci mu to funguje, a pak se hrozně diví, že s jinou implementací to nefunguje.
Třeba ta "jednoduchá posloupnost řádků" u HTTP/1. Co když se tam někde vyskytne dvojtečka? Co ta mezera, je povinná jedna, může jich být víc, může být vynechaná? Co když se tam vyskytne CRLF, nebo jen jeden z těch znaků? Hned to přestává být tak jednoduché, při parsování musíte ty hlavičky procházet znak po znaku a jejich obsah se musí v paměti kopírovat, když je chcete dál předat jako dvojici textových řetězců. Ve skutečnosti se tedy dají hlavičky HTTP/2 strojově zpracovat mnohem efektivněji, než hlavičky HTTP/1.1.
V reálném provozu HTTP/1.x se vyskytují všelijaká porušení specifikace. Např. opakování neopakovatelných hlaviček (Content-Type), i tak zásadních pro parsování zprávy, jako je Content-Length, vynechání jména hlavičky (včetně dvojtečky) v Set-Cookie, nebo závislost na rozdělení hlaviček do paketů. Proč bych si měl myslet, že implementace binárního protokolu specifikaci porušovat nebudou?
Dvojtečka neovlivní rozdělení textu do řádků. Zpracování různých variant mezer a CRLF je popsané v RFC. Pravidla sice nejsou úplně triviální a liší se mezi RFC 2616 a 7230, ale pořád jsou mnohem jednodušší, než binární (de)kódování hlaviček v HTTP/2. Když chcete předat jako dvojici textových řetězců hlavičku z HTTP/2, tak musíte hlavičky dekódovat, takže obsah budete v paměti taky kopírovat. V HTTP/1 v C teoreticky nic kopírovat nemusím, protože první znak (whitespace nebo dvojtečku) za jménem hlavičky a první znak za hodnotou (whitespace, CR, nebo LF) nahradím nulovým bajtem a mám dva řetězce.
Chybný počet hlaviček je jiný typ chyby, a může se objevit úplně stejně u textového i binárního protokolu. Mně tedy dekódování binárních hlaviček v HTTP/2 připadá mnohem jednodušší, než dekódování hlaviček v HTTP/1.1. V případě HTTP/2 není kopírování potřeba - hlavičky tam nejsou komprimované jako posloupnost oktetů (třeba gzipem), "komprimace" hlaviček je postavena na vynechání opakujících se hlaviček. To nahrazení nulovým bajtem v HTTP/1.1 je sice hezké, ale na začátku nevíte, jak je ta hlavička dlouhá a jak velký pro ni máte vyhradit buffer. Navíc jakmile v té hlavičce máte nějaké uvozovky, je zpracování hlavičky komplikovanější, než jen přidání nulového bajtu.
Z 57 stran specifikace kódování hlaviček HTTP/2 je pro implementaci relevantních cca 23 stran. Pro implementaci parsování hlaviček v HTTP/1 je relevantní sekce 3 do 3.2.4 včetně z RFC 7230, cca 7 stran. Z toho se velká část týká hodnot hlaviček, které vypadnou z dekódování binárního formátu, a je tedy relevantní i pro HTTP/2. V HTTP/1 si vystačíte s rozlámáním textu podle (CR)LF, nalezením dvojteček, odstraněním nadbytečných mezer a převodem jmen hlaviček na malá písmena. Dostanete hodnoty, které musíte dál zpracovat úplně stejně v obou protokolech, včetně případných uvozovek.
Když se budeme bavit o zakódování, tak místo celého algoritmu pro HTTP/2 si vystačíte pro každou hlavičku s přidáním Jméno + ": " + Hodnota + CRLF na výstup odesílaný do sítě. Jestli nevěříte, že je HTTP/1 jednodušší, zkuste si obě verze protokolu implementovat.
A takhle právě vznikají ty chybné implementace. V případě HTTP/2 by vás asi nenapadlo to implementovat jen tak od oka, aniž byste si přečetl specifikaci. S HTTP/1.1 to klidně uděláte, protože máte pocit, že je to jednoduchý textový protokol, kvůli kterému specifikaci číst nemusíte. Kdybyste si tu specifikaci přečetl, zjistil byste, že hlavičky mohou být víceřádkové, protože uvozovky mají speciální význam. Takže nestačí text rozlámat podle CRLF, ale musíte obsah hlavičky parsovat, odstraňovat uvozovky a CRLF v uvozovkách nepovažovat za ukončení hlavičky.
Není mi jasné, proč si myslíte, že bych HTTP/1.1 implementoval "jen tak od oka", a že ho považuji za jednoduchý textový protokol, ale myslíte si to špatně :-)
Možnost interpretovat specifikaci HTTP tak, že CRLF uvnitř uvozovek, přesněji uvnitř uvozovek (quoted-string) nebo závorek (comment) a zapsané pomocí quoted-pair ("\" CHAR), neznamená ukončení hlavičky, byla chyba v RFC 2616, která byla opravena v RFC 7230. Hlavičky mohou být víceřádkové, pokud pokračovací řádek začíná mezerou nebo tabulátorem. I tohle je v RFC 7230 označené jako deprecated.
Už jsem to tu psal čtyřikrát. Rozdělit text na řádky podle CRLF a každý řádek podle dvojtečky (plus několik technických detailů), nebo naopak poskládat dvojice jméno-hodnota do textu HTTP/1.x zprávy, je mnohem jednodušší, než kódování a dekódování podle HTTP/2. Jestli tomu nevěříte, tak si to zkuste implementovat.
Zkusím Vám to vysvětlit ještě jednou... Některé chybné implementace mohou vzniknout tak, že někdo považuje čtení specifikace za zbytečné. Jiné chybné specifikace zase vznikají tak, že si někdo sice přečte specifikaci, ale něco v ní špatně pochopí nebo prostě v implementaci udělá chybu. Pravděpodobnost takových chyb stoupá s délkou a složitostí specifikace.
Nicméně já jsem psal o implementaci podle specifikace. Když budu implementovat parsování hlaviček HTTP/1.1 a budu si chtít maximálně ulehčit práci, tak rozlámu text podle CRLF na jednotlivé hlavičky. Každou rozdělím podle dvojtečky na jméno a hodnotu. Jakmile najdu někde samostatné CR nebo LF, nečtu dál, vracím 400 Bad Request a zavírám TCP spojení. Když najdu mezeru nebo tabulátor na začátku řádku nebo před dvojtečkou, nebo kdekoliv najdu znak ze skupiny CTL (kromě SP a HTAB), reaguji stejně. Z hodnoty odříznu whitespace na začátku a na konci. Dostanu posloupnost hlaviček ve formě dvojic řetězců jméno-hodnota. A mám hotovo, dodržel jsem specifikaci (RFC 7230). Víceřádkové hlavičky mě nezajímají: na obs-fold mám explicitně povoleno vrátit 400, Vámi zmiňovaná možnost CRLF v quoted-string (možná pomocí quoted-pair) je v RFC 7230 zakázaná a i podle RFC 2616 je její validita hodně diskutabilní. Ještě zbývá odesílání hlaviček, ale to je jeden printf.
A teď si předchozí odstavec porovnejte s kódováním a dekódováním podle HTTP/2.
Nějak se vám ten jednoduchý algoritmus komplikuje. Přitom jste popsal ten nejjednodušší případ - rozumný klient i server samozřejmě musí počítat i s tím, co RFC povoluje ale nedoporučuje. A teď si představte, že byste implementoval reálný klient nebo server, a chtěl se vypořádat i s tím, že někdo kašle na RFC a hlavičky vypisuje jedním printf. (No, v tomhle případě byste brzy zjistil, že to řešení nemá.)
Porovnal jsem si to už dávno a HTTP/2 mi z toho vychází jako jednodušší na praktickou implementaci.
Ty složitější případy nejsou zase o tolik složitější. Co je "rozumný klient i server" závisí na okolnostech. Ale asi už Vám přestávám rozumět. Ono RFC zakazuje printf? Napsal jsem popis implementace na jeden odstavec. Každý programátor si snad dokáže představit, jak by vypadal odpovídající kód. Předpokládám, že dokážete kódování a dekódování hlaviček v HTTP/2 popsat také v jednom odstavci, nebo dokonce předvést ten jednodušší kód.
Obávám se, že tato naše diskuse ztrácí smysl a nikoho nezajímá. Proto v ní nehodlám pokračovat.
Popsal jste popis chybné implementace. To nic nevypovídá o tom, jak by vypadala správná implementace. RFC nezakazuje printf, ale když použijete jenom printf, vaše implementace nebude odpovídat RFC. Stačí si to dát dohromady s tím vaším popisem parsování. Jak by to asi dopadlo, kdyby v hodnotě hlavičky, kterou byste poslal do printf, bylo CRLF?
Pan Beran porovnával porovnatelné: poslední verzi protokolu HTTP (1.1) s novou verzí protokolu HTTP (2.0). Vy porovnáváte neporovnatelné: tvrdíte, že server podporující HTTP/1.1 musí umět odpovídat i na HTTP/1.0 a starší. To ale bude muset server odpovídající na HTTP/2.0 (nějakou dobu) také. Pokud budu mít HTTP/2.0 only server, tak úplně stejně mohu mít HTTP/1.0 only server.
Já jsem porovnával praktickou implementaci – tj. mám v jednom serveru vedle sebe implementaci „jednoduchého textového protokolu“, tj. HTTP 1.0 a nějaký kompromis HTTP 1.1 mezi RFC 2616 a RFC 7230–7235, a implementaci binárního protokolu HTTP 2.0. Že jsou to na jedné straně tři protokoly a na druhé jenom jeden? No jo, ale to je právě ta komplikovanost „jednoduchého textového protokolu“, kde se vstup „jednoduše“ rozdělí podle řádek – jenže pak se ukáže, že nikdo neví, co je to řádek, a v každé verzi protokolu je to jinak (dokonce pro jednu verzi protokolu existují dva nekompatibilní standardy).
Mimochodem, samotné parsování HTTP hlaviček v HTTP 2.0 je oproti HTTP 1.x triviální, trochu to komplikuje kešování hlaviček. Takže kdybychom chtěli porovnávat porovnatelné vaším způsobem, bylo by nutné porovnávat parsování hlaviček dle RFC 7230 a parsování hlaviček (bez kešování) dle HTTP 2.0.
Ty porušení specifikace IMO často vznikají tak, že si nějaký matlal řekne "To je text, to je jasný. RFC je pro sraby." A už to smolí. U binárního protokolu bych podobných expertů čekal trochu míň.
Samozřejmě, že budou existovat porušení specifikace. Tam to bude úplně na stejno s textovými protokoly. Bude se to flíkovat dodatečně (prasárny se moc nedají předvídat ani u textu) a jen pokud se to vyplatí.
http://http2.github.io/http2-spec/compression.html - dejte to někomu implementovat a potom se jej zeptejte, zda je jednodušší parsovat text :-)