Prolomení šifrovaného protokolu HTTPS

Vyděsil vás titulek článku? Vlastně to bylo tak trochu cílem. Mnoho z nás totiž žije v klamné představě, že nasazení důvěryhodného SSL certifikátu a správná konfigurace webového serveru postačuje k zajištění důvěryhodného a nečitelného přenosu dat mezi serverem a klientem. Naše přesvědčení potvrzuje fakt, že na tomto předpokladu staví celý svět online byznysu.

Jak by řekli matematici – použití HTTPS protokolu je pro zajištění takové komunikace nutná, nikoliv však postačující podmínka. Díky tomu, že je HTTPS protokol páteří seriózního internetu, je také velmi zajímavý pro útočníky, kteří by jeho prolomením hodně získali.

Předpokládejme nyní, že jste na váš web nasadili SSL/TLS certifikát – třebas i ten zdarma poskytovaný iniciativou Let’s Encrypt. Svědomitě jste nastavili svůj webový server tak, že si z SSL testu odnášíte známku ne menší než A+. Vaše stránky tím pádem nastavují i hlavičku HSTS. Možná jste vaši doménu zavedli i do preload listu prohlížečů, která zajistí, že vaši návštěvníci nepadnou do pasti „man-in-the-middle“ útočníka, který by je o HTTPS protokol připravil.

Zkrátka a prostě,  co se týká ochrany svých zákazníků, jste opravdu pečliví. A teď si představte, že přes to přese všechno existuje způsob, jak se může útočník k obsahu přenášených dat dostat.

Heist & Breach přichází na scénu

K citlivým údajům uživatele operujícího na vašem webu se útočník s největší pravděpodobností dostane pomocí kombinace dvou útočných technik zvaných Heist (anglický ekvivalent slova „loupež“”, zveřejněna v srpnu 2016) a Breach (anglický ekvivalent slova „průlom“, zveřejněna v srpnu 2013). A co k tomu potřebuje?

  • Vaši neznalost problému
  • nasazení kompresního algoritmu na odpovědi webserveru
  • stránku zrcadlící hodnotu vstupního parametru, která zároveň obsahuje utajovaný „citlivý údaj“

Schválně se zamyslete, jestli náhodou tyto podmínky nesplňujete.

Trochu vám s přemýšlením pomůžeme. Kompresi nejspíš na webserveru nasazenou máte, dělají to tak (téměř) všichni – dost to totiž zrychluje odezvy webu, hlavně na mobilních sítích. Přece jen je rozdíl stahovat 2MB nebo 400kB. Nejspíš budete používat gzip, možná SPDY nebo novější HTTP/2, koneckonců si to můžete hned teď ověřit.

Teď potřebujeme na vašem webu najít nějakou stránku, co otiskne do svého těla obsah vstupního parametru, který jí předáme. Velmi vhodnými adepty jsou např. vyhledávací formuláře, které do výstupní stránky typicky napíší, jaký vyhledávaný výraz byl vložený a kolik výsledků mu vyhovuje. Ideální stránky jsou takové, kde parametr dokážeme protlačit GET požadavkem, ale i s POSTem si útočník hravě poradí. Každý větší web má podobných stránek či URL desítky.

A nyní už nám stačí jen najít ty, kde se zároveň nachází nějaký „citlivý údaj“. Asi nejsme tak bláhoví, abychom někde zobrazovali celá čísla platebních karet, ale pro někoho může být citlivým údajem třeba číslo občanského průkazu, rodné číslo nebo jen adresa bydliště.

To, po čem útočník nejspíš půjde, bude tzv. CSRF token, kterým chráníte provedení všech důležitých akcí na vašem webu (pokud ne, zapomeňte na tento článek, protože máte daleko větší problém). Tento token bývá platný pro sezení uživatele a pokud jej útočník získá, může na vašem webu jménem přihlášeného uživatele provádět libovolné akce nechráněné sekundárním ověřením (opětovným zadáním hesla, potvrzením přes SMS či e-mail apod.). Ano mluvíme zde o útoku typu Cross-Site-Request-Forgery, před kterým vás má právě CSRF token chránit.

Jak bude takový útok vypadat z pohledu uživatele?

Uživatel vejde na váš web, přihlásí se a následně záložku zavře bez odhlášení, případně  ji nechá otevřenou, ale vedle otevře novou záložku prohlížeče, v níž dál pracuje. Jinými slovy, váš server má pro uživatele stále otevřené sezení, ve kterém je přihlášen.

V jiné záložce samozřejmě prochází další weby a buď rovnou přijde na web útočníka, nebo otevře web, který má ve svém těle vloženou HTML5 reklamu (sic!) z běžného inzertního systému, do něhož útočník vložil vedle oživení reklamy i speciální JavaScriptový kód využívající výše zmíněné techniky útoku.

Jakmile uživatel přijde na web s takto napadenou reklamou, útočný kód v několika vteřinách vyextrahuje cílenými HTTP dotazy na konkrétní stránku vašeho webu citlivý údaj uživatele. Pokud se jedná o CSRF token, provede následně dalšími HTTP požadavky na pozadí aktivní operace ve jménu daného uživatele a to všechno aniž by uživatel  něco tušil.

Jediná věc, která hraje ve váš prospěch, je to, že útok musí být skutečně dobře zacílený na váš web a útočník jej musí velmi dobře znát. Provozovatelé populárních CMS/e-commerce systémů jsou v tomto samozřejmě v nevýhodě, protože čím víc je systém rozšířený, tím je pro útočníky zajímavější.

Jak je to všechno možné?

Teď maličko zabředneme do technikálií.

Breach

Breach využívá základního principu fungování kompresních algoritmů, které vyhledávají duplicity v původním obsahu a zjednodušeně je nahrazují „odkazem“ na první výskyt.

Pokud máme řetězec unikátních znaků ABCD, není možné z něj nic odebrat, aniž by došlo ke ztrátě informace. Řetězec ABCDAB je již možné zkrátit o poslední dva znaky nahrazením duplicitního řetězce AB odkazem na první dva znaky textu (tedy na 1CD1, kde 1 zastupuje kombinaci AB).

Pokud nám tedy útočník dokáže vnutit parametr, který server otiskne do výstupní odpovědi dané stránky a čirou náhodou bude obsah tohoto parametru shodný s nějakou jinou částí výstupní stránky (třeba s naším tajemstvím), musí být výsledná délka komprimovaného obsahu stránky o patřičný počet znaků menší.

Pro útočníka je na této technice skvělé to, že se nemusí snažit hádat celé tajemství najednou – to by bylo stále kombinačně příliš náročné (např. už 4 znakové tajemství v Base32 dává něco málo přes milion kombinací). Tento princip totiž funguje už i na jeden jediný znak tajemství, takže nám jej může vykrást postupně po jednom znaku, což je daleko jednoduší (v našem příkladě 4znakového tajemství v Base32 mu bude stačit max. 4×32 = 128 pokusů).

Heist

Druhým do party je Heist, který umožní útočníkovu JavaScriptu ZMĚŘIT odezvu serveru, na který útočí. Prohlížeč mu samozřejmě neumožní přistoupit k informaci o počtu bajtů komprimované odezvy serveru. Nicméně pomocí performance API lze zjistit čas mezi prvním a posledním doručeným bajtem odpovědi a při znalosti fungování sítí je z toho možné odvodit, jak byla zakomprimovaná odpověď velká.

Zní to jednoduše, ale je to pokročilá magie, která využívá nízkoúrovňových detailů, jako jsou velikosti TCP oken – jejich pomocí se útočník může dopátrat, jak velké množství výplňového textu je nutné vygenerovat k tomu, aby klient (útočník) donutil server rozdělit odpověď do více TCP oken v případě neduplicitního znaku a méně v případě správně uhodnutého znaku. Časový rozdíl mezi TCP okny je totiž již měřitelný a odlišitelný z pohledu JavaScriptového kódu.

Celá technika je komplexní a hraje v ní roli řada dalších detailů. V nouzi je třeba pomoci si i statistikou, ale vše jsou to pro chytrou hlavu řešitelné věci. Milióny tupějších hlav budou schopny útok využít v podobě zabaleného exploitu.

Jak se proti tomu lze bránit?

A jsme u meritu věci. Bránit se tomu nedá, respektive pouze omezeně. Stoprocentní ochrana je prakticky nepoužitelná. Co radí objevitelé Breach útoku?

  • Vypnout HTTP kompresi – to nechcete.
  • Oddělit chráněné informace od reflektovaných vstupů – to se dělá dost obtížně, např. CSRF token dost úzce souvisí s parametry odesílanými uživatelem.
  • Zajistit náhodný obsah chráněných informace v každé odpovědi – nepoužitelné např. u čísla občanského průkazu – nebo jej maskovat další šifrou.
  • Přidávat ke každé odpovědi náhodný počet náhodných znaků – jenže druhým dechem autoři dodávají, že to útočníka pouze trochu zdrží, ale stejně mu nezabrání citlivá data nakonec získat.
  • Omezit počet požadavků klienta – opět to útočníka jen zdrží, ale nezastaví.

Ze všech možností připadá v úvahu pouze ta třetí a to jen někde.

Aspoň trošku…

Řekněme, že na webu nejsou žádné přímo viditelné citlivé údaje zákazníka, po kterých by útočník mohl bažit. Zbude nám CSRF token, který potřebujeme, abychom mohli uživatele chránit proti CSRF útokům. Tento token naštěstí před výše popsaným útokem ochránit dokážeme.

Pro každý požadavek můžeme generovat unikátní CSRF token. Tento nápad už tu byl, ale bohužel se ukázal jako velmi nepraktický (např. při pohybu v historii prohlížeče zpět nebo při částečných aktualizacích obsahu stránek ajaxem začne pracovat proti nám).

Proto je lepší v každém požadavku zamaskovat CSRF token platný pro celé sezení uživatele jednoduchou XOR šifrou s náhodným saltem, který povede k naprosto rozdílnému obsahu CSRF tokenu pro každou odpověď, ale při zpětném poslání na server budeme schopni z maskované varianty a saltu původní CSRF token zpětně odvodit.

Maskovaný CSRF token bude vypadat takto:

CSRF_TOKEN xor SALT + SALT

Tj. při konstantním CSRF = "abc" a náhodným SALT = "def" a výsledkem XOR operace = "753" do stránky otiskneme "753def". Z tohoto řetězce jsme schopni na straně serveru znovu vypočíst původní CSRF token "abc". V dalším requestu nám vyjde náhodný SALT = "123", což změní XOR na "b9f" a výsledná hodnota potom na "b9f123", ze které ale opět dostaneme jednoduše původní CSRF tokendefdefdefdefdefdef "abc".

Nechce-li se vám to programovat, sáhněte třebas po naší Java implementaci výše uvedeného algoritmu. Používáte-li Spring Security, počkejte si na verzi 5.x, kde uvedený algoritmus (snad) zaimplementují přímo do této knihovny.

Nemůže to vyřešit někdo za vás?

Zatím se neví o ničem, co by bylo možné implementovat do webových serverů nebo prohlížečů a dokázalo efektivně odstínit Heist/Breach útok. IETF právě pracuje na draftu, který by nás mohl definitivně zbavit hrozby CSRF útoků. Draft se jmenuje First-Party-Only-Cookies a prozatím je implementován v prohlížečích Chrome a Opera (další budou přibývat). Draft počítá s tím, že cookies, které váš web označí příznakem SameSite, nebude prohlížeč posílat ze stránek pocházejících z jiné domény, než pro jaké je cookie platná.

Pokud tedy příznakem SameSite označíte session cookie, budou všechny požadavky z externích stránek na váš web vypadat jako dotazy anonymního uživatele, tj. nebudou sdílet přihlášení uživatele, který má váš web otevřený v jiném tabu, nebo jej opustil neodhlášený. Tím pádem nikdo zvenčí nebude moci zneužít jeho autentizace k nekalým operacím na pozadí.

Máte z toho těžkou hlavu?

My taky :-)

Článek byl publikován na firemním webu FG Forrest.