Graj bezpiecznie w elementach iframe w trybie piaskownicy

Tworzenie zaawansowanych treści w internecie niemal nieuniknienie umieszczanie komponentów i treści, na które nie masz wpływu. Widżety innych firm mogą zwiększać zaangażowanie i odegrać kluczową rolę wygoda użytkowania i treści użytkowników są czasem ważniejsze niż treść natywna witryny. powstrzymanie się od jednego z tych narzędzi nie jest dobrym rozwiązaniem, zwiększają ryzyko wystąpienia w witrynie błędu Coś BadTM. Każdy umieszczony widżet (każda reklama, każdy widżet mediów społecznościowych) może wektora ataku dla osób o złych zamiarach:

Polityka bezpieczeństwa treści (CSP) mogą zmniejszyć ryzyko związane z obydwoma tymi typami treści, możesz dodawać do białej listy zaufane źródła skryptów oraz treści. To ważny krok we właściwym kierunku, ale warto podkreślić, Ochrona, którą zapewnia większość dyrektyw CSP, jest binarna: zasób jest lub nie jest dozwolona. Czasami warto powiedzieć „Nie jestem Naprawdę ufam temu źródłu treści, ale to naprawdę piękne! Umieść proszę, przeglądarkę, ale nie pozwól, żeby zepsuła moją witrynę”.

Najmniejsze uprawnienia

W gruncie rzeczy szukamy mechanizmu, który pozwoliłby nam udostępniać treści umieścić tylko minimalny poziom ich umiejętności niezbędnych do wykonania jego zadania. Jeśli widżet nie musi otwierać nowego okna, odbierając dostęp do window.open, urazić. Jeśli wtyczka nie wymaga Flasha, to wyłączenie obsługi wtyczek nie powinno być . Zapewniamy najwyższy poziom bezpieczeństwa, jeśli przestrzegamy zasady jak najmniejszej privilege i zablokuj wszystkich funkcji, które nie są bezpośrednio związane z funkcją, którą chcemy uwzględnić których użyć. Dzięki temu nie musimy już ślepo ufać danym nie będzie korzystać z uprawnień, które nie powinny być używane. it po prostu nie będą mieć dostępu do tych funkcji.

Elementy iframe to pierwszy krok na drodze do stworzenia dobrej struktury tego typu. Wczytywanie niezaufanych komponentów w iframe umożliwia pomiar odległości między aplikacją a treścią, którą chcesz wczytać. treści w ramce, nie będzie mieć dostępu do DOM strony ani danych przechowywanych lokalnie. mieć możliwość rysowania w dowolnych miejscach na stronie; jest ograniczony do i konturów ramki. Ten podział nie jest jednak prawdziwie trwały. Zawarta strona nadal ma kilka opcji irytujących lub złośliwych działań: autoodtwarzanie wideo, wtyczki i wyskakujące okienka to tylko wierzchołek góry lodowej.

Atrybut sandbox elementu iframe daje nam wszystko, czego potrzeba do zaostrzania ograniczeń dotyczących treści w ramkach. Możemy poinstruuj przeglądarkę, aby wczytywała zawartość określonej ramki z niskimi uprawnieniami umożliwiając działanie tylko tych części funkcji, które są niezbędne co musisz zrobić.

Nieprawdziwe, ale zweryfikowane

„Tweet” na Twitterze to świetny przykład funkcji, która pozwala bezpiecznie umieszczone w witrynie za pomocą piaskownicy. Twitter umożliwia umieszczanie w elemencie iframe następującym kodem:

<iframe src="https://platform.twitter.com/widgets/tweet_button.html"
        style="border: 0; width:130px; height:20px;"></iframe>

Aby dowiedzieć się, co możemy zablokować, przyjrzyjmy się dokładniej funkcjom wymagany przycisk. Kod HTML wczytywany do ramki wykonuje fragment kodu JavaScript z serwerów Twittera, co generuje wyskakujące okienko z tweetowanie po kliknięciu. Ten interfejs wymaga dostępu do plików cookie, aby powiązać tweet z właściwym kontem. Potrzebna jest też możliwość aby przesłać formularz tweetowania. To już wszystko. ramka nie musi żadnych wtyczek, nie musi przechodzić do okna najwyższego poziomu ani żadnego i wielu innych elementów. Ponieważ nie są potrzebne te uprawnienia, usuńmy je, umieszczając zawartość klatki w piaskownicy.

Piaskownica działa na podstawie białej listy. Na początek usuniemy wszystkie a następnie ponownie włączyć poszczególne funkcje, dodając określonych flag do konfiguracji piaskownicy. W widżecie Twittera włączyć obsługę języka JavaScript, wyskakujących okienek, przesyłania formularzy oraz plików cookie. Możemy to zrobić, dodając do elementu iframe atrybut sandbox z parametrem Następująca wartość:

<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>

To wszystko. Obejmował on wszystkie wymagane możliwości. będzie pomocna odmowa jej dostępu do wszelkich uprawnień, których nie mieliśmy bezpośrednio przyznać go za pomocą wartości atrybutu sandbox.

Szczegółowa kontrola nad zdolnościami

W powyższym przykładzie zauważyliśmy kilka możliwych flag piaskownicy, więc teraz przyjrzyj się dokładniej wewnętrznemu działaniu atrybutu.

Jeśli element iframe z pustym atrybutem piaskownicy zostanie w pełni umieszczony w piaskownicy, dokument w ramce zostanie poddany z tymi ograniczeniami:

  • JavaScript nie zostanie wykonany w dokumencie w ramce. Obejmuje to nie tylko JavaScript ładowany bezpośrednio przez tagi skryptu, ale również przez wbudowane moduły obsługi zdarzeń oraz javascript:. Oznacza to również, że treść zawarta w tagach noscript , dokładnie tak, jakby użytkownik sam wyłączył skrypt.
  • Dokument w ramce jest wczytywany do unikalnego punktu początkowego, co oznacza, że wszystkie sprawdzanie tej samej domeny zakończy się niepowodzeniem; unikalne źródła nie pasują do żadnego innego źródła a nawet samych siebie. Oznacza to między innymi, że dokument nie będzie w żaden sposób dostępu do danych zapisanych w plikach cookie dowolnego źródła lub innych mechanizmach przechowywania danych; (Pamięć DOM, Indexed DB itp.).
  • Dokument w ramce nie może tworzyć nowych okien ani okien (za pomocą interfejsu window.open ani target="_blank").
  • Nie można przesłać formularzy.
  • Wtyczki nie zostaną wczytane.
  • Dokument w ramce może poruszać się tylko po nim, a nie do elementu nadrzędnego nadrzędnego. Ustawienie window.top.location spowoduje zgłoszenie wyjątku i kliknięcie linku z target="_top" nie będzie działać.
  • Funkcje, które uruchamiają się automatycznie (automatyczne elementy formularza, autoodtwarzanie filmy itp.) są blokowane.
  • Nie można uzyskać blokady wskaźnika.
  • Atrybut seamless jest ignorowany w przypadku iframes, który zawiera dokument w ramce.

To przykuwająco drastyczny charakter, ponieważ dokument wczytał się do w pełni piaskownicy iframe nie niesie ze sobą bardzo małego ryzyka. Oczywiście nie może to też przynieść znaczącej wartości: w przypadku niektórych treści statycznych może dać się wyłączyć pełną piaskownicę, ale większość na czas, żeby trochę się rozluźnić.

Z wyjątkiem wtyczek każde z tych ograniczeń mogą znieść przez dodanie flagi do wartości atrybutu piaskownicy. Dokumenty w trybie piaskownicy nigdy uruchamianie wtyczek (wtyczki są kodem natywnym poza piaskownicą), ale wszystko inne jest dozwolone. gra:

  • allow-forms umożliwia przesyłanie formularzy.
  • allow-popups zezwala na wyskakujące okienka (szok!).
  • allow-pointer-lock zezwala na (niespodziankę) blokadę wskaźnika.
  • allow-same-origin umożliwia zachowanie pochodzenia dokumentu. wczytano strony od https://example.com/ zachowa dostęp do danych tego źródła.
  • allow-scripts umożliwia wykonywanie JavaScriptu i udostępnia funkcje automatycznie uruchamiają się automatycznie (ponieważ wdrożenie za pomocą JavaScriptu byłoby bardzo proste).
  • allow-top-navigation pozwala dokumentowi wyjść poza ramkę o nawigowanie po oknie najwyższego poziomu.

Mając to na uwadze, możemy dokładnie ocenić, flagi piaskownicy w przykładzie powyżej z Twittera:

  • Element allow-scripts jest wymagany, ponieważ strona wczytywana w ramce jest uruchamiana JavaScript do obsługi interakcji użytkownika.
  • Wymagany jest identyfikator allow-popups, ponieważ po kliknięciu przycisku pojawi się formularz tweeta w nowym formacie okno.
  • Wymagany jest atrybut allow-forms, ponieważ formularz dotyczący tweetów powinien być możliwy do przesłania.
  • Element allow-same-origin jest niezbędny, ponieważ w przeciwnym razie pliki cookie twitter.com będzie niedostępny i użytkownik nie będzie mógł zalogować się, aby opublikować formularz.

Warto zwrócić uwagę, że flagi piaskownicy zastosowane do klatki również zostaną zastosowane do wszystkich okien lub ramek utworzonych w piaskownicy. Oznacza to, że należy dodać element allow-forms do piaskownicy ramki, mimo że formularz istnieje tylko w oknie, w którym pojawia się ramka.

Po ustawieniu atrybutu sandbox widżet uzyskuje tylko te uprawnienia, do których a funkcje takie jak wtyczki, górna nawigacja czy blokada wskaźnika pozostaną bez zmian. Użytkownik został zablokowany. Zmniejszyliśmy ryzyko umieszczenia widżetu na stronie. Nie spowoduje to żadnych niekorzystnych skutków. Jest to korzystne dla wszystkich zainteresowanych.

Rozdział uprawnień

Umieszczanie w piaskownicy treści osób trzecich w celu uruchomienia ich niezaufanego kodu w środowisku o niskich uprawnieniach jest oczywiście korzystne. A co z masz własny kod? Zaufanie sobie, prawda? Dlaczego więc przejmować się piaskownicą?

Odwróćmy to pytanie: jeśli kod nie wymaga wtyczek, dlaczego warto dostęp do wtyczek? To przywilej, którego nigdy nie można użyć, a w najgorszym razie – w którym hakerzy mogą wejść do środka. Każdy ma swój kod i właściwie każda aplikacja jest podatna na wykorzystanie w jeden sposób czy coś innego. Piaskownica we własny kod oznacza, że nawet wtedy, gdy atakujący zdoła spowoduje zablokowanie aplikacji, nie uzyskają one pełnego dostępu do źródło aplikacji; będą mogli wykonywać tylko czynności dostępne dla aplikacji, robisz. Nadal kiepsko, ale nie tak źle.

Możesz jeszcze bardziej zmniejszyć ryzyko, dzieląc aplikację na elementów logicznych i podziel się z nimi na „piaskownice” przy jak najniższych uprawnieniach. Ta technika jest bardzo powszechna w kodzie natywnym. Na przykład Chrome ulega awarii. w proces przeglądarki o zaawansowanych uprawnieniach z dostępem do lokalnego dysku twardego i mogą nawiązywać połączenia sieciowe, a także wiele procesów renderujących o niskich uprawnieniach, Google wykonuje ciężkie zadanie, analizując niezaufane treści. Mechanizmy renderowania nie muszą klikać na dysku, przeglądarka przekazuje mu wszystkie informacje potrzebne do renderować stronę. Nawet jeśli sprytny haker znajdzie sposób zniszczenia mechanizmu renderowania, ale nie zaszły zbyt daleko, ponieważ sam mechanizm renderowania nie jest w stanie znacząco wpłynąć na wyniki: Wszystkie uprawnienia dostępu o wysokich uprawnieniach muszą być kierowane przez proces przeglądarki. Hakerzy będą musieli znaleźć kilka dziur w różnych częściach systemu wyrządzenia krzywdy, co znacznie zmniejsza ryzyko ich zniszczenia.

Bezpieczne piaskownice eval()

Tryb piaskownicy postMessage API, że sukces tego modelu jest dość łatwy do zastosowania w sieci. Fragmenty aplikacja może mieszkać w piaskownicy iframe, a dokument nadrzędny może broker komunikacji między nimi, publikując wiadomości i nasłuchując odpowiedzi. Taka struktura powoduje, że luki w zabezpieczeniach w każdym wyrządzają minimalne szkody. Zaletą takiego rozwiązania jest zmuszenie użytkowników do tworzyć jasne punkty integracji, dzięki czemu wiesz dokładnie, należy zachować ostrożność podczas weryfikowania danych wejściowych i wyjściowych. Przyjrzyjmy się przykładowi zabawki. aby zobaczyć, jak to się sprawdzi.

Evalbox to ciekawa aplikacja, który pobiera ciąg znaków i ocenia go jako JavaScript. Nieźle, prawda? Tylko co czekaliśmy na Ciebie przez tyle długich lat. To dość niebezpieczne, aplikacji, ponieważ umożliwienie wykonania dowolnego JavaScriptu oznacza, i wszystkie dane, które ma do zaoferowania źródło, są gotowe do przechwycenia. Ograniczymy ryzyko że kod jest wykonywany wewnątrz piaskownicy, co jest znacznie bezpieczniejsze. Przeprowadzimy ten proces przez kod na zewnątrz, zaczynając od zawartości ramki:

<!-- frame.html -->
<!DOCTYPE html>
<html>
    <head>
    <title>Evalbox's Frame</title>
    <script>
        window.addEventListener('message', function (e) {
        var mainWindow = e.source;
        var result = '';
        try {
            result = eval(e.data);
        } catch (e) {
            result = 'eval() threw an exception.';
        }
        mainWindow.postMessage(result, event.origin);
        });
    </script>
    </head>
</html>

W ramce znajduje się minimalny dokument, który po prostu nasłuchuje wiadomości z elementu nadrzędnego, łącząc się ze zdarzeniem message obiektu window. Za każdym razem, gdy element nadrzędny wykonuje postMessage na treści elementu iframe, to zdarzenie , dając nam dostęp do ciągu, którego wymaga rodzic .

W module obsługi pobierany jest atrybut source zdarzenia, który jest elementem nadrzędnym okno. Wykorzystamy go, żeby wysłać informacje o wynikach naszej ciężkiej pracy, gdy tylko gotowe. Odpowiedź wykonamy na najcięższą pracę, przekazując przekazane nam dane eval() To połączenie zostało zakończone blokadą prób jako zablokowane operacje wewnątrz piaskownicy iframe będzie często generować wyjątki DOM; Złapiemy i zgłoś to nam. Wyniki publikujemy do okna nadrzędnego. To całkiem proste.

Element nadrzędny jest równie prosty. Utworzymy mały interfejs użytkownika za pomocą interfejsu textarea dla kodu i button do wykonania. Pobierzemy frame.html przez iframe w trybie piaskownicy, zezwalający tylko na wykonywanie skryptu:

<textarea id='code'></textarea>
<button id='safe'>eval() in a sandboxed frame.</button>
<iframe sandbox='allow-scripts'
        id='sandboxed'
        src='frame.html'></iframe>

Dostarczymy teraz kod do realizacji. Najpierw słuchamy odpowiedzi iframe i alert() je użytkownikom. Prawdopodobnie jest to prawdziwa aplikacja zrobi coś mniej irytującego:

window.addEventListener('message',
    function (e) {
        // Sandboxed iframes which lack the 'allow-same-origin'
        // header have "null" rather than a valid origin. This means you still
        // have to be careful about accepting data via the messaging API you
        // create. Check that source, and validate those inputs!
        var frame = document.getElementById('sandboxed');
        if (e.origin === "null" &amp;&amp; e.source === frame.contentWindow)
        alert('Result: ' + e.data);
    });

Następnie dołączymy moduł obsługi zdarzeń do kliknięć elementu button. Gdy użytkownik pobiorą aktualną zawartość pliku textarea i przekażemy ją do funkcji ramka do wykonania:

function evaluate() {
    var frame = document.getElementById('sandboxed');
    var code = document.getElementById('code').value;
    // Note that we're sending the message to "*", rather than some specific
    // origin. Sandboxed iframes which lack the 'allow-same-origin' header
    // don't have an origin which you can target: you'll have to send to any
    // origin, which might alow some esoteric attacks. Validate your output!
    frame.contentWindow.postMessage(code, '*');
}

document.getElementById('safe').addEventListener('click', evaluate);

Łatwe, prawda? Stworzyliśmy bardzo prosty interfejs API do oceny i możemy być pewni, oceniany kod nie ma dostępu do informacji poufnych, takich jak pliki cookie lub pamięć DOM. Podobnie oceniony kod nie może ładować wtyczek, wyświetlać nowych okien, lub innych irytujących lub szkodliwych działań.

To samo możesz zrobić z własnym kodem, dzieląc aplikacje monolityczne na są jednozadaniowe. Każdy z nich można dołączyć do prostego interfejsu API do obsługi wiadomości, jak napisaliśmy powyżej. Okno nadrzędne o wysokim uprawnieniach może pełnić funkcję wysyła wiadomości do konkretnych modułów do obsługi jak najmniejszych przywilejów podczas pracy, słuchania oczekiwania na wyniki dbając o to, aby każdy moduł był dostarczany tylko w przypadku wymaganych informacji.

Pamiętaj jednak, że musisz bardzo ostrożnie obchodzić się z treścią w ramce pochodzi z tego samego pochodzenia co element nadrzędny. Jeśli strona Aplikacja https://example.com/ umieszcza w ramach piaskownicy inną stronę w tym samym źródle który zawiera flagi allow-same-origin i allow-scripts, strona w ramce może sięgnąć do elementu nadrzędnego i usunąć atrybut piaskownicy całkowicie.

Graj w piaskownicy

Piaskownica jest obecnie dostępna w różnych przeglądarkach: Firefox 17+, IE10+ oraz Chrome w momencie tworzenia (oczywiście kan ). Stosuję: sandbox do iframes dodanego przez Ciebie atrybutu umożliwia nadanie pewnych uprawnień wyświetlanych treści, wyłącznie uprawnienia, które są niezbędne aby działały prawidłowo. Dzięki temu możesz zmniejszyć ryzyko z uwzględnieniem treści osób trzecich, niezależnie od tego, jest już możliwe dzięki Content Security Zasady.

Piaskownica to też skuteczna metoda ograniczania ryzyka, że sprytne oprogramowanie atakujący będzie mógł wykorzystać luki w Twoim kodzie. Oddzielając aplikacji monolitycznej w zestawie usług działających w trybie piaskownicy, z których każda odpowiada zbiór samodzielnych funkcji, hakerzy będą musieli które przełamują tylko określone klatki, treści, ale też ich administratora. To jest o wiele trudniejsze, zwłaszcza że na kontrolerze można znacznie ograniczyć w zakresie ochrony danych. Możesz poświęcić czas na sprawdzenie tego kodu, jeśli poproś go o pomoc w pozostałych kwestiach.

Nie oznacza to, że piaskownica jest kompletnym rozwiązaniem i bezpieczeństwa w internecie. Zapewnia rozbudowaną obronę. kontroli nad uprawnieniami użytkowników nie możemy na razie polegać na obsłudze przeglądarek użytkowników (jeśli kontrolujesz klientów klientów, czyli środowisko firmowe, na przykład: hura!). Kiedyś, ale obecnie piaskownica to kolejna warstwa wzmacnianie zabezpieczeń, ale nie stanowi kompletnej obrony, na którą na której można polegać. Mimo to warstwy są świetne. Zalecamy skorzystanie z jeden.

Dalsza lektura

  • Rozdział uprawnień w aplikacjach HTML5” jest interesującym dokumentem na temat projektowania niewielkiego schematu, i jego zastosowanie w trzech istniejących aplikacjach HTML5.

  • Piaskownica może być jeszcze bardziej elastyczna w połączeniu z dwoma innymi nowymi elementami iframe atrybuty: srcdoc, i seamless. Pierwszy pozwala wypełnić ramkę treścią bez dodatkowych kosztów żądania HTTP, które zezwala na przepływ stylu do treści w ramce. Obie mają raczej słabą obsługę przeglądarek (Chrome i WebKit) wieczory). ale w przyszłości może to być interesująca kombinacja. Możesz: na przykład komentarze w trybie piaskownicy do artykułu za pomocą tego kodu:

        <iframe sandbox seamless
                srcdoc="<p>This is a user's comment!
                           It can't execute script!
                           Hooray for safety!</p>"></iframe>