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.

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="...">
</iframe>
), bude rámec maximálně sandboxovaný, tj.:

  • 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 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 nebo  target="_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 z target="_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 atribut  seamless.

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í okna
  • allow-pointer-lock povolí uzamčení ukazatele myši
  • allow-same-origin povolí dokumentu zachovat jeho origin, tj. dokument z https://example.com/  bude mít přístup k datům z této domény
  • allow-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 a seamless . 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 v iframe. 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>

Vystudoval jsem biochemii. Vymyslel a založil Zdroják. Aktuálně ho vedu. Nejsem váš hodný tatínek, který vás bude brát za ručičku, ale zlý moderátor diskusí. Smiřte se s tím!

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 9

Přehled komentářů

petr Díky
Yossarian sandbox?
Martin Hassman Re: sandbox?
Yossarian Re: sandbox?
Martin Hassman Re: sandbox?
peter otazka
Martin Hassman Re: otazka
peter Re: otazka
Martin Hassman Re: otazka
Zdroj: https://www.zdrojak.cz/?p=3772