Když John Postel v roce 1980 definoval pravidlo robustnosti (známé také jako Postelův zákon), tak se zdálo být rozumné jej definovat jako: „Buď liberální v tom, co přijímáš, ale buď striktní v tom, co vysíláš.“ O pár let později bylo toto pravidlo rozšířeno v RFC 1122 o požadavek nejen přežít divoké prostředí špatně naformátovaných paketů, ale také nadále spolupracovat a komunikovat s implementacemi, které se takto neslušně chovají. Internet byl ve svých počátcích a bylo těžké odhadovat, jaká všechna zařízení budou do sítě připojena a jak dobře nebo špatně budou naprogramována.
Nicméně zpátky k návrhu internetových protokolů. Již o deset let později v roce 2001 popisuje Marshall Rose v RFC 3117 problémy, které přináší aplikace principu robustnosti do interoperability aplikací. Představte si, že máme dvě implementace:
- implementaci Locke, kterou psal hodně šikovný programátor a docela si s ní vyhrál, takže je velmi liberální a dokáže přijmout a zpracovat libovolně naformátovaný paket a…
- implementaci Demosthenes, kterou psal programátor hodně ve spěchu a posílá takové pakety, ze kterých se dělá trochu špatně i směrovačům po cestě.
Locke si s Démosthenem v klidu dokáží povídat. Locke se sice občas diví, co to Démosthenés říká, ale vcelku dobře si rozumějí a komunikace volně plyne. To se ovšem radikálně mění ve chvíli, kdy na scénu přichází implementace Rochester, kde byl programátor velmi striktní a naprogramoval Rochestera tak, že přesně odpovídá specifikaci protokolu a odmítá jakékoli odchylky od standardu, zatímco si Locke s Rochesterem může bez problému popovídat (ostatně jsou oba dva angličané). Dokonce pro Lockeho je komunikace s Rochesterem jednodušší, protože oba dva při komunikaci dodržují správný komunikační protokol. Naopak Démosthenés má se svou antickou řečtinou najednou problém. Démosthenés se může snažit mluvit s Rochesterem jak chce, ale ten mu prostě nemůže rozumět, protože nemluví společným jazykem.
A co by na to řekli All Blacks? Kdyby se o Postelově zákonu dozvěděli v půlce prosince minulého roku, tak by asi zareagovali takto:
Proč? Správci novozélandské domény .NZ v půlce prosince dokončili proces implementace DNSSEC, vypublikovali správný klíč a poslali jej do kořenové zóny. Následně byli upozorněni, že jejich klíč má nezvyklou sekvenci znaků v místě, kde je uveden RSA exponent. Pro srovnání si tento rozdíl pojďme ukázat konkrétně.
Klíč pro doménu .CZ vypadá takto:
cz. IN DNSKEY 257 3 10 ( AwEAAaVU8EMQrZ6Tix2zBaAmizMQ7W0m94qSJUXV4eVW S9ZpXh9t1uj8U/B5Nnqge4G0Te0/NJIqflihZKXs8Hyh JqjF852RKnvNWPu2wMujYjHP0T4lIhu4rTym9+sPNsfi oqvMyyDeqyhVPx21nvLW5oaKjaLd3XJxijRbDTddRU97 mJVVS50PKdDmh5n/4KdRKV7ifR2Ap8L1bvUiCOxl4GAq LoXft+L896bkVj6mefdCSyYaCbgsDc2+10ZBOSF1t89N J6O1yO+y5/7vS3dYKEqj+p4ygaCY0spvrhZxncUeASix g224bNYZM5TLk2/YoKgAEjaIoCwu7SAXB5iUvLU= ) ; key id = 14568
Pokud rozkódujeme prvních pár znaků, dostaneme následující výstup:
$ dig dnskey cz +short | grep '^257' | awk '{print $4}' | base64 -d | xxd -l 12 -b 0000000: 00000011 00000001 00000000 00000001 10100101 01010100 .....T 0000006: 11110000 01000011 00010000 10101101 10011110 10010011 .C....
Délka exponentu je uvedena na prvním místě (00000011), tj. exponent je dlouhý tři bajty. Exponent je v tomto případě 65537 (00000001 00000000 00000001).
DNSSEC klíč pro novozélandskou doménu vypadal takto:
nz. IN DNSKEY 257 3 8 ( BAABAAGwfTiEoh71o6S55+Mdy1qqVRnpKY1VHznrv+wx rPfvRGB5VivFFPFN+33fsaTxJQTceOtOna7IKxTffj6p bBG4a9vtk2FqF551IwXomKWJnzRVKqYzuAx+Os/5gLIN BH7+qRWAkJwCdQXIaJGyGmshkO5Ci5Ex5Cm3EZCeVrie 0fLI03Ufjuhi6IJ7gLzjEWw84faLIxWHEj8w0UVcXfaI 2VL0oUC/R+9RaO7BJKv93ZqoZhTOSg9nH51qfubbK6FM svOWEyVcUNE6NESYEbuCiUByKfxanvzzYUUCzmm+JwV7 7Ebj3XZSBnWnA2ylLXQ4+HD84rnqb1SgGXu9HZYn ) ; key id = 2517
Opět rozkódujeme prvních pár bajtů:
dig dnskey nz +short | grep '^257' | awk '{print $4}' | base64 -d | xxd -l 12 -b 0000000: 00000100 00000000 00000001 00000000 00000001 10110000 ...... 0000006: 01111101 00111000 10000100 10100010 00011110 11110101 }8....
Již na první pohled je vidět, že exponent je v tomto případě delší (00000100), tj. 4 bajty. Nicméně hodnota exponentu (00000000 00000001 00000000 00000001) zůstává stejná, tedy rovna 65537.
V čem je tedy zádrhel? Dle standardu RFC 3110, který definuje kódování RSA klíčů pro použití v DNS, jsou počáteční nuly v exponentu zakázány. A nyní se dostáváme zpátky k počátečnímu sporu Postel vs Rose.
Správci novozélandské domény samozřejmě nasazení DNSSEC klíče pečlivě otestovali a vše správně fungovalo. Jinými slovy Démosthenés si při testování povídal s Lockem. Nakonec se bohužel ukázalo, že na scéně se skrýval Rochester v podobě implementace rekurzivního resolveru od firmy Nominum, která je při dekódování exponentu velmi striktní a po přijetí klíče novozélandské domény selhala při DNSSEC validaci. Toto nakonec vedlo k tomu, že bylo zapotřebí klíč novozélandské domény opravit a do kořenové zóny poslat klíč ve správném kódování.
Jaké z toho nakonec plyne poučení? Druhá část pravidla robustnosti stále platí, je zapotřebí být velmi striktní při implementaci protokolu, aby byla zajištěna dobrá interoperabilita. Nicméně je jistě ke zvážení, jestli nebýt striktní také při implementaci přijímací části, aby bylo možné odhalit chyby včas již při testování.
A co si myslíte vy? Je lepší být v implementaci striktní nebo liberální?
Ondřej Surý
P.S. Tento článek, respektive odkaz na něj, zahajuje naši komunikaci na Google Plus. Pokud tedy tuto sociální síť využíváte a chcete být informováni o našich projektech a aktivitách, přidejte si nás do svých kruhů.
Podobný problém s „počátečními nulami“ se objevil i v případě ASN.1 BER/DER kódování OID v X.509 certifikátech. ASN.1 specifikace to zakazuje, ale mnoho TLS klientů to tiše toleruje s různými výsledky.
Pak se na to našel i útok: http://ioactive.com/pdfs/PKILayerCake.pdf (strana 15). Bylo na to náchylné MS Crypto API (snad už dnes opraveno).
Závěr: „liberální“ maskování chyb protistrany vede k těžko objevitelným zranitelnostem.
Díky akceptování různých zhůvěřilostí v HTML je práce browserů „vélmi slložitá“. Kdyby se od začátku HTML striktně validovalo, mohl být web jednodušší :).
JJ, stritktní implementace SMTP s DNS pro Exchange 2000 versus Unix admin nešvar kdy MX odkazoval na CNAME přičmž tehdy dle RFC měla být vazba MX na Alias. Normálně vše fungovalo ping i telnet protože standartní DNS resolving našel CNAME, ale SMTP v Exchange 2000 se ptalo následně přímo na A záznam. V té době mi nezbylo nic než posílat dotčeným vlastníkům takto nesprávně zapsaným DNS přímo příslušné RFC protože odmítali věřit, že mají něco špatně. Prej vše funguje.Proto se vždy otevírá otázka co je správně, volnější přístup nebo striktnější. V mém popsaném příkladě můžeme říci, že striktnost MS byla na škodu na druhou stranu, ale následně se nemůžeme spolehnout na standart a jeho chování a v jiném případě by mohlo dojít díky liberálnímu přístupu k nežádoucím chybám. Rozsoudit tohle není jednoduché. Výhody a nevýhody vidím na obou stranách.
Dává smysl oba přístupy kombinovat: vstup si vykládat liberálně, ale chyby detekovat a hlasitě na ně upozorňovat.
Největší guláš je podle mě ve zpracování HTML, prohlížeč dokáže zpracovat a zobrazit velmi špatně napsané HTML i když každý trochu jinak – to je výhoda pro uživatele pokaždé se mu alespoň něco něco zobrazí.
Na druhou stranu, drakonické parsování by velice zrychlilo a zjednodušilo kód prohlížeče – to by přineslo méně chyb a rychlejší prohlížeč (v každém kódu může být chyba, nejrychlejší kód je takový který se nemusí vůbec vykonat, který tam není).
Já jsem pro striktní implementaci daných pravidel, standardů. Jsem pro odladění chyb ještě vývojáře než řešit odlišné chování různých implementací při zpracovávání „mírně chybných“ vstupů u uživatelů (teď nemyslím jenom HTML).
Marek.