Sicher in Sandbox-iFrames spielen

Um im heutigen Web ein umfassendes Erlebnis zu schaffen, müssen fast zwangsläufig Komponenten und Inhalte einbetten, über die Sie keine Kontrolle haben. Drittanbieter-Widgets können Interaktionen fördern und spielen eine entscheidende Rolle User Experience und von Nutzern erstellte Inhalte sind oft sogar als der native Content einer Website. Auf beides zu verzichten ist keine Option, Sie beide erhöhen das Risiko, dass auf Ihrer Website ein schädliches Verhalten erkannt wird. Jedes jede Ihrer Anzeigen und Social-Media-Widgets ist ein potenzielles Angriffsvektor für böswillige Absichten:

Content Security Policy (CSP) Risiken mindern, die mit diesen beiden Inhaltstypen verbunden sind, indem können Sie vertrauenswürdige Quellen für Skript- und sonstigen Inhalte. Das ist ein wichtiger Schritt in die richtige Richtung, Der Schutz, den die meisten CSP-Anweisungen bieten, ist binär: Die Ressource ist zulässig sein oder nicht. Manchmal ist es nützlich zu sagen: dass ich dieser Inhaltsquelle vertraue, aber sie sieht so hübsch aus. Einbetten Browser, aber lassen Sie meine Website nicht kaputt.“

Geringste Berechtigung

Wir suchen also nach einem Mechanismus, mit dem wir Inhalte erlauben können, nur das geringste Leistungsniveau einbetten, das für die Ausführung dieser Aufgabe erforderlich ist. Wenn ein Widget Es muss kein neues Fenster geöffnet werden. Der Zugriff auf „window.open“ kann nicht verhindert werden. wehgetan. Ist Flash nicht erforderlich, sollte die Deaktivierung der Plug-in-Unterstützung Problem. Wir sind so sicher wie möglich, wenn wir uns nach dem Prinzip der geringsten alle Funktionen, die nicht direkt relevant für die Funktionen sind, die wir uns wünschen zu verwenden. Das hat zur Folge, dass wir nicht mehr blind darauf vertrauen müssen, von eingebetteten Inhalten keine Rechte ausüben, die sie nicht in Anspruch nehmen sollten. Es einfach gar keinen Zugriff auf die Funktionen haben.

iframe-Elemente sind der erste Schritt zu einem guten Framework für eine solche Lösung. Das Laden einer nicht vertrauenswürdigen Komponente in eine iframe bietet ein Maß für die Trennung zwischen Ihrer Anwendung und den Inhalten, die Sie laden möchten. Geframete Inhalte hat keinen Zugriff auf das DOM Ihrer Seite oder auf lokal gespeicherte Daten. Sie können an beliebigen Positionen auf der Seite zeichnen. ist der Umfang auf die des Rahmens. Die Trennung ist jedoch nicht wirklich zuverlässig. Enthaltene Seite bietet aber weiterhin eine Reihe von Optionen für lästige oder schädliche Verhaltensweisen: Videos, Plug-ins und Pop-ups sind die Spitze des Eisbergs.

Das sandbox-Attribut des iframe-Elements erhalten wir genau das, was wir brauchen, um die Einschränkungen für Inhalte in Frames zu verstärken. Wir können den Browser anweisen, den Inhalt eines bestimmten Frames mit niedriger Berechtigung zu laden sodass nur bestimmte Funktionen genutzt werden können, die Arbeit erledigen muss.

Twust, aber überprüfen

„Tweet“ von Twitter ist ein gutes Beispiel für Funktionen, über eine Sandbox sicher auf Ihrer Website eingebettet. In Twitter können Sie die Schaltfläche über einen iFrame durch den folgenden Code:

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

Um herauszufinden, welche Funktionen gesperrt werden können, für die Schaltfläche erforderlich ist. Der in den Frame geladene HTML-Code führt von den Twitter-Servern und generiert ein Popup-Fenster mit einer auf die Tweet-Oberfläche. Diese Schnittstelle benötigt Zugriff auf die verwendet werden, um den Tweet mit dem richtigen Konto zu verknüpfen, und muss die Möglichkeit haben, um das Tweet-Formular einzureichen. Das wars auch schon. muss der Frame keine Plug-ins laden, muss nicht das oberste Fenster geöffnet oder und viele weitere Funktionen. Da diese Berechtigungen nicht benötigt werden, indem wir den Inhalt des Frames in einer Sandbox ausführen.

Die Sandbox-Technologie basiert auf einer weißen Liste. Zunächst entfernen wir alle Berechtigungen erteilen, und dann einzelne Funktionen wieder aktivieren, indem Sie spezifische Flags an die Konfiguration der Sandbox anpassen. Für das Twitter-Widget aktivierte JavaScript, Pop-ups, Formulareinreichungen und die Cookies. Dazu fügen wir dem iframe ein sandbox-Attribut mit der folgenden Wert:

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

Das war's. Wir haben dem Frame alle Funktionen gegeben, die er braucht, kann dieser den Zugriff auf alle Berechtigungen verweigern, explizit über den Wert des Attributs sandbox gewähren.

Detaillierte Kontrolle über Funktionen

Im Beispiel oben haben wir einige mögliche Sandbox-Flags gesehen. genauer auf die Funktionsweise des Attributs eingehen.

Bei einem iFrame mit einem leeren Sandbox-Attribut wird das in einem Frame angezeigte Dokument vollständig in einer Sandbox ausgeführt. gelten die folgenden Einschränkungen:

  • JavaScript wird im Rahmen des Dokuments nicht ausgeführt. Dazu gehören nicht nur JavaScript, das explizit über Script-Tags geladen wird, aber auch Inline-Event-Handler und javascript: URLs. Das bedeutet auch, dass Inhalte in noscript-Tags wird angezeigt, genau so, als hätte der Nutzer das Skript selbst deaktiviert.
  • Das gerahmte Dokument wird in einen eindeutigen Ursprung geladen, was bedeutet, dass alle Prüfungen am selben Ursprung schlagen fehl. eindeutige Ursprünge stimmen mit nie anderen Ursprüngen überein, nicht und sogar sich selbst. Das bedeutet unter anderem, dass das Dokument keine Zugriff auf Daten, die in den Cookies aller Ursprungsserver oder in anderen Speichermechanismen gespeichert sind (DOM-Speicher, indexierte Datenbank usw.).
  • Das gerahmte Dokument kann keine neuen Fenster oder Dialogfelder erstellen (über window.open oder target="_blank").
  • Formulare können nicht gesendet werden.
  • Plug-ins werden nicht geladen.
  • Das in einem Frame angezeigte Dokument kann nur sich selbst navigieren, nicht das übergeordnete Element der obersten Ebene. Wenn Sie window.top.location festlegen, wird eine Ausnahme ausgelöst und ein Klick auf den Link mit target="_top" hat keine Auswirkungen.
  • Funktionen, die automatisch ausgelöst werden (automatisch fokussierte Formularelemente, automatische Wiedergabe) Videos usw.) gesperrt werden.
  • Zeigersperre kann nicht abgerufen werden.
  • Das Attribut seamless wird für iframes, die das gerahmte Dokument enthält, ignoriert.

Das ist recht drakonisch und ein Dokument wird in eine iframe-Sandbox mit vollständiger Sandbox-Technologie geladen. stellt ein sehr geringes Risiko dar. Natürlich hat es auch keine große Bedeutung: Sie für einige statische Inhalte eine vollständige Sandbox kombinieren zu können, aber die meisten in der Regel etwas lockerer werden.

Mit Ausnahme von Plug-ins kann jede dieser Einschränkungen aufgehoben werden, dem Wert des Sandbox-Attributs ein Flag hinzufügen. Dokumente, die in einer Sandbox ausgeführt werden, Plug-ins ausführen, da Plug-ins nativer Code ohne Sandbox-Technologie sind, alles andere aber fair ist Spiel:

  • Über allow-forms können Formulare gesendet werden.
  • allow-popups lässt (schock!) Pop-ups zu.
  • allow-pointer-lock ermöglicht (überraschend!) Zeigersperre.
  • Mit allow-same-origin kann der Ursprung des Dokuments beibehalten werden. Seiten geladen aus https://example.com/ behält Zugriff auf die Daten dieses Ursprungs.
  • allow-scripts ermöglicht die Ausführung von JavaScript und bietet außerdem folgende Funktionen: werden automatisch ausgelöst, da die Implementierung über JavaScript sehr einfach wäre.
  • Mit allow-top-navigation kann das Dokument aus dem Frame herausragen, im obersten Fenster navigieren.

Mit diesen Überlegungen können wir genau abschätzen, warum wir das spezifische Sandboxing-Flags im obigen Twitter-Beispiel:

  • allow-scripts ist erforderlich, da die in den Frame geladene Seite einige JavaScript-Code für Nutzerinteraktionen.
  • allow-popups ist erforderlich, da die Schaltfläche in einem neuen Fenster für Tweets eingeblendet wird. .
  • allow-forms ist erforderlich, da das Tweet-Formular eingereicht werden kann.
  • allow-same-origin ist erforderlich, wie die Cookies von twitter.com andernfalls nicht zugänglich sein und der Nutzer konnte sich nicht anmelden, um das Formular zu senden.

Beachten Sie, dass die Sandboxing-Flags, die für einen Frame gelten, gelten für alle in der Sandbox erstellten Fenster oder Frames. Das bedeutet, dass wir um allow-forms zur Sandbox des Frames hinzuzufügen, obwohl das Formular nur vorhanden ist in das Fenster ein, in dem sich der Frame öffnet.

Wenn das Attribut sandbox vorhanden ist, erhält das Widget nur die Berechtigungen, die es Funktionen wie Plug-ins, Navigation oben und Zeigersperre bleiben erhalten. blockiert. Wir haben das Risiko der Einbettung des Widgets ohne Beeinträchtigungen verringert. Das ist ein Gewinn für alle Beteiligten.

Rechtetrennung

Die Ausführung von Drittanbieterinhalten in einer Sandbox, um nicht vertrauenswürdigen Code in einem ist natürlich von Vorteil. Aber was ist mit Ihrem eigenen Code? Sie vertrauen sich selbst, oder? Warum sollten Sie sich also Gedanken über die Sandbox machen?

Ich würde diese Frage umkehren: Wenn Ihr Code keine Plug-ins benötigt, warum sollten Sie auf Plug-ins zugreifen? Im besten Fall ist es ein Privileg, das Sie nie nutzen, im schlimmsten Fall könnte ein Angriffsvektor möglich sein, um in die Tür zu gelangen. Jeder Code hat und praktisch jede Anwendung ist in gewisser Weise anfällig für Angriffe. oder ein anderes. Wenn Sie Ihren eigenen Code in einer Sandbox ausführen, können Angreifer auch dann, Ihre Anwendung stört, erhält diese Person keinen vollständigen Zugriff auf die den Ursprung der Anwendung, können sie nur Dinge tun, die die Anwendung auch kann. was Sie tun können. Immer noch schlecht, aber nicht so schlimm, wie es sein könnte.

Sie können das Risiko noch weiter reduzieren, indem Sie Ihre Anwendung in logische Teile und führt die Sandbox mit minimalen Berechtigungen aus. Diese Technik ist bei nativem Code sehr verbreitet: Chrome führt zum Beispiel einen Fehler durch. in einen Browserprozess mit hohen Berechtigungen, der Zugriff auf die lokale Festplatte hat, Netzwerkverbindungen und viele Renderer-Prozesse mit niedriger Berechtigung, nicht vertrauenswürdige Inhalte zu parsen. Renderer müssen die auf dem Laufwerk, sorgt der Browser dafür, dass alle Informationen zur Verfügung stehen, um eine Seite zu rendern. Selbst wenn ein cleverer Hacker einen Renderer korrumpieren könnte, ist noch nicht sehr weit gekommen, da der Renderer alleine nicht viel Interesse wecken kann: müssen alle Zugriffsrechte mit hoher Berechtigung durch den Prozess des Browsers geleitet werden. Angreifer müssen verschiedene Lücken in verschiedenen Bereichen des Systems finden Schaden anzurichten, was das Risiko eines erfolgreichen Kaufs erheblich verringert.

eval() sicher in einer Sandbox ausführen

Mit Sandboxing und der postMessage API, die lässt sich der Erfolg dieses Modells recht einfach auf das Web anwenden. Stücke von Ihre Anwendung kann in iframes in einer Sandbox leben und das übergeordnete Dokument kann Kommunikation zwischen ihnen, indem sie Nachrichten posten und Antworten. Mit einer solchen Struktur wird sichergestellt, dass App den minimalen Schaden anrichten. Es hat auch den Vorteil, dass Sie klare Integrationspunkte erstellen, damit Sie genau wissen, wo Sie bei der Validierung der Ein- und Ausgabe. Sehen wir uns ein Spielzeugbeispiel an. um zu sehen, wie das funktionieren könnte.

Evalbox ist eine spannende Anwendung, das einen String als JavaScript auswertet. Wow, oder? Genau was auf die Sie schon lange gewartet haben. Es ist ziemlich gefährlich, Da die Ausführung von beliebigem JavaScript-Code bedeutet, und alle Daten, die ein Ursprung zu bieten hat, sind verfügbar. Wir minimieren das Risiko Bad ThingsTM passiert, indem es sicherstellt, dass der Code innerhalb einer Sandbox ausgeführt wird, Das macht die App um einiges sicherer. Wir arbeiten uns den Code aus der von innen nach außen, beginnend mit dem Inhalt des Frames:

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

Im Frame befindet sich ein minimales Dokument, das einfach auf Nachrichten wartet. vom übergeordneten Element entfernt, indem es in das message-Ereignis des window-Objekts eingebunden wird. Immer wenn das übergeordnete Element postMessage für die Inhalte des iFrames ausführt, wird dieses Ereignis wird ausgelöst und gibt uns Zugriff auf den String, den das übergeordnete Element ausführen können.

Im Handler nehmen wir das Attribut source des Ereignisses, bei dem es sich um das übergeordnete . Wir verwenden diese E-Mail-Adresse, um das Ergebnis unserer harten Arbeit zurückzusenden, sobald wir fertig. Dann übernehmen wir den schwierigen Teil, indem wir die uns vorliegenden Daten eval() Dieser Anruf wurde als verbotene Vorgänge in einen „Versuchsblock“ eingeschlossen innerhalb eines in einer Sandbox ausgeführten iframes werden häufig DOM-Ausnahmen generiert. fangen wir und melden Sie stattdessen eine Fehlermeldung. Schließlich veröffentlichen wir das Ergebnis zum übergeordneten Fenster zurück. Das ist ziemlich einfach.

Das übergeordnete Element ist ähnlich unkompliziert. Wir erstellen eine winzige Benutzeroberfläche mit einem textarea für Code und ein button für die Ausführung. Wir rufen frame.html über eine wurde für iframe in einer Sandbox ausgeführt, wodurch nur die Skriptausführung zugelassen ist:

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

Jetzt werden wir die Dinge zur Ausführung verkabeln. Zuerst warten wir auf Antworten von iframe und alert() an unsere Nutzer. Vermutlich eine echte Anwendung etwas weniger ärgerlich tun würden:

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);
    });

Als Nächstes verknüpfen wir einen Event-Handler, um auf das button zu klicken. Wenn Nutzende kopieren wir den aktuellen Inhalt von textarea und übergeben ihn an die Frame für die Ausführung:

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

Ganz einfach, oder? Wir haben eine sehr einfache Evaluierungs-API erstellt, bewerteter Code keinen Zugriff auf vertrauliche Informationen wie Cookies DOM-Speicher erstellen. Ebenso kann ausgewerteter Code keine Plug-ins laden, keine neuen Fenster öffnen oder andere lästige oder schädliche Aktivitäten.

Sie können dasselbe für Ihren eigenen Code tun, indem Sie monolithische Anwendungen in zweckgebundenen Komponenten. Jedes Paket lässt sich in einer einfachen Messaging-API zusammenfassen, so wie oben beschrieben. Das übergeordnete Fenster mit hohen Berechtigungen kann als und Disponenten, die Nachrichten an bestimmte Module die geringstmöglichen Berechtigungen haben, um ihre Aufgaben zu erledigen, um sicherzustellen, dass jedes Modul nur mit den erforderlichen Informationen versorgt wird.

Beachten Sie jedoch, dass Sie beim Umgang mit Inhalten in Frames vorsichtig sein müssen. die denselben Ursprung haben wie das übergeordnete Element. Wenn eine Seite auf https://example.com/ setzt eine weitere Seite desselben Ursprungs mit einer Sandbox ein mit den Flags allow-same-origin und allow-scripts. kann die in einem Frame angezeigte Seite bis in die übergeordnete Seite reichen und das Sandbox-Attribut entfernen. .

In der Sandbox spielen

Sandboxing ist jetzt in einer Vielzahl von Browsern verfügbar: Firefox 17 und höher, IE10+ und Chrome (Caniuse hat natürlich eine aktuelle Supporttabelle). sandbox anwenden können Sie dem iframes-Attribut bestimmte Berechtigungen angezeigt werden, nur die Berechtigungen, die für den damit sie ordnungsgemäß funktionieren. So können Sie Risiken reduzieren, die mit der Einbeziehung von Inhalten Dritter in Verbindung stehen, mit Content Security Richtlinien:

Sandboxing ist darüber hinaus eine effektive Methode, um das Risiko zu reduzieren, dass ein cleverer können Angreifer Lücken in Ihrem Code ausnutzen. Durch das Trennen eines in einer Reihe von Sandbox-Diensten, die jeweils für eine Funktion nicht nutzen können, werden Angreifer gezwungen, nur bestimmte Frames kompromittieren, sondern auch deren Verantwortliche. Das ist ein schwierigere Aufgabe, zumal die Steuerung stark reduziert werden kann. zu berücksichtigen. Sie können Ihre sicherheitsbezogenen Bemühungen aufwenden, diesen Code zu überprüfen, wenn Sie bitten Sie den Browser um Hilfe.

Das bedeutet nicht, dass die Sandbox eine Komplettlösung für das Problem Sicherheit im Internet. Sie bietet tief greifende Verteidigung, die Kontrolle über die können Sie sich noch nicht bei allen Ihre Nutzer (wenn Sie die Kontrolle über Ihre Nutzer, Kunden - eine Unternehmensumgebung, zum Beispiel - hurra!). Irgendwann ist die Sandbox jedoch eine weitere Ebene zur Stärkung Ihrer Abwehr, ist es keine vollständige Abwehr, können Sie sich allein darauf verlassen. Die Ebenen sind dennoch hervorragend. Ich schlage vor, diese Funktion eins.

Weiterführende Literatur

  • Aufteilung von Berechtigungen in HTML5-Anwendungen ist ein interessanter Artikel, der das Design eines kleinen Frameworks behandelt. und die Anwendung auf drei bestehende HTML5-Apps.

  • Die Sandboxing-Technologie kann in Kombination mit zwei weiteren neuen iFrames noch flexibler sein. Attribute: srcdoc, und seamless. Mit der erstgenannten API können Sie einen Frame mit Inhalten füllen, ohne dass eine HTTP-Anfrage erstellt, bei der Stil in den gerahmten Inhalt eingefügt werden kann. Browserunterstützung für beide ist im Moment ziemlich schlecht (Chrome und WebKit). Nachts). aber in Zukunft wird eine interessante Kombination sein. Sie könnten: zum Beispiel die Sandbox-Kommentare zu einem Artikel über den folgenden Code:

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