Bezpečný sandboxovaný iframe

V HTML5 můžeme pomocí atributu sandbox vkládat na obsah iframe rozličná bezpečnostní omezení. Pojďme se podívat, jaká to jsou a jak je můžeme používat.
Nálepky:
Tento text je zkráceným překladem článku Play safely in sandboxed IFrames, jehož autorem je Mike West a je zde zveřejněn pod licencí CC-BY-3.0.
Na dnešním webu se často nedokážeme úplně vyhnout vkládání komponent, nad kterými nemáme žádnou kontrolu. Widgety od třetích stran mohou hrát pro UX důležitou roli. A každý takový vložený widget je možným místem útoku.
Princip nejnižších privilegií
Hodil by se nám mechanismus, který by vloženému obsahu přidělil minimální oprávnění, která ještě postačí k tomu, aby mohl správně fungovat. Pokud widget nevyžaduje vyskakovací okna, nebude mu vadit, když mu odepřeme přístup k window.open
, pokud nepotřebuje Flash, nevznikne žádný problém, když mu vypneme podporu pluginů apod. Následujeme tím tzv. princip nejnižších privilegií.
Tím prvním krokem správným směrem je použití iframe
. To zajistí oddělení obsahu vkládaného z nedůvěryhodného zdroje od naší aplikace. Obsah z iframe
se nedostane k DOMu naší stránky ani k datům, která máme uložena lokálně, ani nemůže kreslit na libovolnou pozici ve stránce, je omezen na prostor rámce. Oddělení samo o sobě není ovšem dostatečné. Obsah v iframe
má stále mnoho možností, jak uživatele obtěžovat nebo zmást: automaticky spuštěné video, pluginy a vyskakovací okna jsou jen špičkou ledovce.
Tady nám pomůže atributsandbox
prvku iframe
, který umí oprávnění rámce omezit. Můžeme tak prohlížeči říct, aby nahrál do daného rámce obsah a přidělil mu jen omezenou sadu privilegií.
Takovým dobrým příkladem je tlačítko „Tweetni“, to můžeme vložit pomocí iframe tímto kódem:
<iframe src="https://platform.twitter.com/widgets/tweet_button.html" style="border: 0; width:130px; height:20px;"></iframe>
Tlačítko potřebuje přístup k JavaScriptu ze serverů Twitteru a k vyskakovacím oknům. Dále pak ke cookies, aby mohlo tweet přiřadit účtu přihlášeného uživatele, a konečně potřebuje odesílat formuláře, aby mohl uživatel napsaný tweet odeslat. To by mohlo stačit.
Sandboxování konfigurujeme pomocí whitelistu, v našem případě postačí:
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="https://platform.twitter.com/widgets/tweet_button.html" style="border: 0; width:130px; height:20px;"></iframe>
Přehled privilegií
Pokud iframu přidělíme prázdný atribut sandbox ( <iframe sandbox src="...">
), bude rámec maximálně sandboxovaný, tj.:
</iframe>
- JavaScript se v rámci nespustí, to se nevztahuje pouze na JavaScript vložený značkou
script
, ale také na všechny inline handlery a URL typujavascript:
. Bude se zobrazovat obsah ve značcenoscript
, přesně tak, jako kdyby skriptování zakázal sám uživatel. - Dokument v rámci bude nahrán pod samostatný origin, tzn. nebude mít žádný přístup k datům vázaným na doménu, tj. cookies ani webová úložistě (DOM storage, Indexed DB apod.).
- Dokument nemůže vytvářet nová okna a dialogy (např. pomocí
window.open
nebotarget="_blank"
). - Formuláře nebude možné odeslat.
- Pluginy nebudou nahrány.
- Dokument může navigovat pouze obsah sebe sama, zavolání
window.top.location
vyvolá výjimku a kliknutí na odkaz ztarget="_top"
nebude mít žádný efekt. - Automaticky spouštěné vlastnosti jsou zakázány (autofokus formulářových prvků, automatické spouštění videa apod.).
- Dokument nemůže uzamknout ukazatel myši.
- U prvků
iframe
v embedovaném dokumentu bude ignorován atributseamless
.
Všechna tato omezení můžeme zrušit, kromě omezení pluginů, ty v sandboxovaných rámcích nepůjdou spustit nikdy:
allow-forms
povolí odesílání formulářůallow-popups
povolí vyskakovací oknaallow-pointer-lock
povolí uzamčení ukazatele myšiallow-same-origin
povolí dokumentu zachovat jeho origin, tj. dokument zhttps://example.com/
bude mít přístup k datům z této doményallow-scripts
povolí spouštění JavaScriptu a současně povolí automaticky spouštěné vlastnosti (protože by bylo triviální je implementovat JavaScriptem)allow-top-navigation
povolí dokumentu navigaci top-level okna
Připomeňme si, že našemu tweetovacímu tlačítku jsem povolili:
allow-scripts
allow-popups
allow-forms
allow-same-origin
Pozn.: Nesmíme zapomenout zmínit, že sandboxování iframe
se vztahuje i na všechna okna a rámce, které tento iframe
vytvoří. V našem případě jsme museli přidat allow-forms
, i přestože odesílací formulář je umístěn ve vyskakovacím okně.
Demo
Sandboxování si můžete vyzkoušet v jednoduchém demu Evalbox, stačí do něj vložit javascriptový kód a můžete porovnat jeho výsledek spuštěný v obyčejném a v sandboxovaném iframe
.
Podpora prohlížečů
Sandboxování dnes podporuje řada prohlížečů: Firefox 17+, IE10+ a Chrome (viz caniuse).
Další čtení
- Privilege Separation in HTML5 Applications
- Sandboxování může být flexibilnější pomocí dvou atributů
srcdoc
aseamless
. První z nich nám umožní vložit do rámce obsah, aniž bychom musely vytvářet další HTTP požadavek, ten druhý zařídí, aby se kaskádové styly dokumentu vztahovaly i na obsah viframe
. Oba mají jen minimální podporu v prohlížečích (noční buildy Chrome a WebKitu), ale do budoucna se jedná o zajímavou kombinaci, se kterou bude možné sandboxovat například komentáře uživatelů:<iframe sandbox seamless srcdoc="<p>Toto je komentář uživatele! Nemůže spustit žádný skript! To se @spazef0rze nebude ale vůbec líbit 8-)</p>"></iframe>
O této možnosti jsem slyšel poprvé, díky.
Myslim, ze nasledujici dve odrazky si odporuji:
Pokud iframu přidělíme prázdný atribut sandbox ……..
– JavaScript se v rámci nespustí, to se nevztahuje pouze na JavaScript vložený značkou script, ale také na všechny inline handlery a URL typu javascript:. Bude se zobrazovat obsah ve značce noscript, přesně tak, jako kdyby skriptování zakázal sám uživatel.
…
– Dokument může navigovat pouze obsah sebe sama, zavolání window.top.location vyvolá výjimku. (Vsadim obe boty, ze nevyvola :))
Postřeh dobrý, úvaha špatná. Zavolání window.top.location výjimku rozhodně vyvolá, nicméně k onomu zavolání vůbec nedojde. A podobně to platí i pro 2., 3. a 8., které rovněž používají JavaScript.
Mno, a vzhledem k tomu, ze k zavolani nedojde, ani zadna vyjimka vyvolana byt nemuze, ne?
No to je ovšem už jiné tvrzení.
A co ak, is to iframe zmenim, pripadne uplne vymazem atributu sandbox cez firebug resp. aj v chrome a inde a poziadavku odoslem nasledovne, podobne ako ked sa ladia javascriptove veci za pochodu pri testovani? Je toto nejak osetrene v prehliadacoch? Moc sa v tom neorientujem, tak dakujem za vysvetlenie.
To projde jako jakákoliv jiná změna. Nechápu, proč by to mělo být nějak zvlášť ošetření. Není, být nemůže a není důvod, proč by mělo být.
Mozem sa spytat ake je realne pouzitie v praxi, pripadne nejaky web, ktory to pouziva? Neorientujem sa v tom preto ma to zaujima. Dakujem.
Nezkoumal jsem zda to některý ze známých webů už nasadil, není důvod proč ne, v zásadě na většinu dnešních použití iframe se sandbox hodí, minimálně zakázání top-navigation. Pokud vás stále použití nenapadá, počkejte až se sandbox víc rozšíří a bude to jasnější.