438 Stimmen

Frame Buster Buster ... Buster-Code erforderlich

Angenommen, Sie möchten nicht, dass andere Websites Ihre Website in einem "Frame" anzeigen. <iframe> :

<iframe src="http://example.org"></iframe>

Sie fügen also ein Anti-Framing-JavaScript in alle Ihre Seiten ein, das Frames aufhebt:

/* break us out of any containing iframes */
if (top != self) { top.location.replace(self.location.href); }

Ausgezeichnet! Jetzt "sprengen" oder brechen Sie automatisch aus jedem enthaltenen iframe aus. Es gibt nur ein kleines Problem.

Wie sich herausstellte, Ihr Frame-Busting-Code kann geknackt werden , wie hier gezeigt :

<script type="text/javascript">
    var prevent_bust = 0  
    window.onbeforeunload = function() { prevent_bust++ }  
    setInterval(function() {  
      if (prevent_bust > 0) {  
        prevent_bust -= 2  
        window.top.location = 'http://example.org/page-which-responds-with-204'  
      }  
    }, 1)  
</script>

Dieser Code bewirkt Folgendes:

  • erhöht einen Zähler jedes Mal, wenn der Browser versucht, von der aktuellen Seite weg zu navigieren, über die window.onbeforeunload Ereignisbehandler
  • richtet einen Timer ein, der jede Millisekunde über setInterval() und wenn er sieht, dass der Zähler erhöht wird, ändert er den aktuellen Standort zu einem Server, den der Angreifer kontrolliert
  • dass der Server eine Seite mit dem HTTP-Statuscode 204 was den Browser nicht dazu veranlasst, irgendwo zu navigieren

Meine Frage ist - und dies ist mehr ein JavaScript-Rätsel als eine tatsächliche Problem -- wie kann man den Frame-Buster besiegen?

Ich habe mir ein paar Gedanken gemacht, aber bei meinen Tests hat nichts funktioniert:

  • der Versuch, die onbeforeunload Veranstaltung über onbeforeunload = null hatte keine Wirkung
  • Hinzufügen eines alert() das Anhalten des Prozesses lässt den Benutzer wissen, dass es passiert, greift aber in keiner Weise in den Code ein; wenn Sie auf OK klicken, wird das Busting normal fortgesetzt
  • Mir fällt keine Möglichkeit ein, die setInterval() Zeitschaltuhr

Ich bin kein großer JavaScript-Programmierer, also hier ist meine Herausforderung für Sie: Hey Buster, kannst du den Frame-Busting-Buster sprengen?

0 Stimmen

Ich habe im Moment nicht die Möglichkeit, dies zu testen, aber es scheint, dass die einzige Möglichkeit, den sehr schnellen Timer auf der oberen Seite zu blockieren, darin besteht, den einzigen Javascript-Thread, den der Browser hat, mit einer Endlosschleife aktiv zu blockieren. Was ich nicht weiß, ist, ob der Browser in der Lage sein wird, die obere Seite neu zu laden, während dies geschieht. top.location.replace(self.location.href); while(true) { }

6 Stimmen

Ich bin mir nicht sicher, ob der Frame-Buster-Buster tatsächlich funktioniert... wenn ich versuche, ihn zu testen (indem ich auf einen Handler umleite, den ich so eingestellt habe, dass er einen 204 zurückgibt), hindert er mich am Navigieren überall außerhalb der Seite - einschließlich der Eingabe von Daten in die Adressleiste! Ich muss die Browser-Registerkarte schließen und eine neue öffnen, um weiterzukommen. Mit anderen Worten: Ich bin mir nicht sicher, ob das Problem gelöst werden muss, denn der Frame-Buster, der gestoppt werden soll, ist bereits gestoppt... :) (Entweder das oder ich habe meinen Test vermasselt, was nie passieren könnte...) ;)

16 Stimmen

Matt, der oben gepostete Code für den Frame-Buster-Buster definitiv funktioniert. Ein äh Freund von mir hat mir davon erzählt. Oder so. :)

6voto

Johan Stuyts Punkte 61

Alle vorgeschlagenen Lösungen erzwingen unmittelbar eine Änderung der Position des oberen Fensters. Was aber, wenn der Benutzer möchte, dass der Rahmen dort bleibt? Zum Beispiel der obere Rahmen in den Bildergebnissen von Suchmaschinen.

Ich habe einen Prototyp geschrieben, bei dem standardmäßig alle Eingaben (Links, Formulare und Eingabeelemente) deaktiviert sind und/oder nichts tun, wenn sie aktiviert werden.

Wenn ein enthaltender Rahmen erkannt wird, bleiben die Eingaben deaktiviert und es wird eine Warnmeldung am oberen Rand der Seite angezeigt. Die Warnmeldung enthält einen Link, über den eine sichere Version der Seite in einem neuen Fenster geöffnet wird. Dadurch wird verhindert, dass die Seite für Clickjacking verwendet wird, während der Benutzer den Inhalt in anderen Situationen weiterhin betrachten kann.

Wird kein enthaltender Rahmen erkannt, werden die Eingänge aktiviert.

Hier ist der Code. Sie müssen die Standard-HTML-Attribute auf sichere Werte setzen und zusätzliche Attribute hinzufügen, die die tatsächlichen Werte enthalten. Der Code ist wahrscheinlich unvollständig, und für vollständige Sicherheit müssen zusätzliche Attribute (ich denke an Event-Handler) wahrscheinlich auf die gleiche Weise behandelt werden:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
  <head>
    <title></title>
    <script><!--
      function replaceAttributeValuesWithActualOnes( array, attributeName, actualValueAttributeName, additionalProcessor ) {
        for ( var elementIndex = 0; elementIndex < array.length; elementIndex += 1 ) {
          var element = array[ elementIndex ];
          var actualValue = element.getAttribute( actualValueAttributeName );
          if ( actualValue != null ) {
            element[ attributeName ] = actualValue;
          }

          if ( additionalProcessor != null ) {
            additionalProcessor( element );
          }
        }
      }

      function detectFraming() {
        if ( top != self ) {
          document.getElementById( "framingWarning" ).style.display = "block";
        } else {
          replaceAttributeValuesWithActualOnes( document.links, "href", "acme:href" );

          replaceAttributeValuesWithActualOnes( document.forms, "action", "acme:action", function ( form ) {
            replaceAttributeValuesWithActualOnes( form.elements, "disabled", "acme:disabled" );
          });
        }
      }
      // -->
    </script>
  </head>
  <body onload="detectFraming()">
    <div id="framingWarning" style="display: none; border-style: solid; border-width: 4px; border-color: #F00; padding: 6px; background-color: #FFF; color: #F00;">
      <div>
        <b>SECURITY WARNING</b>: Acme App is displayed inside another page.
        To make sure your data is safe this page has been disabled.<br>
        <a href="framing-detection.html" target="_blank" style="color: #090">Continue working safely in a new tab/window</a>
      </div>
    </div>
    <p>
      Content. <a href="#" acme:href="javascript:window.alert( 'Action performed' );">Do something</a>
    </p>
    <form name="acmeForm" action="#" acme:action="real-action.html">
      <p>Name: <input type="text" name="name" value="" disabled="disabled" acme:disabled=""></p>
      <p><input type="submit" name="save" value="Save" disabled="disabled" acme:disabled=""></p>
    </form>
  </body>
</html>

0 Stimmen

Das Problem dabei ist, dass der Framemacher position:absolute verwenden könnte, um die aktive Schaltfläche über den inaktiven Schaltflächen zu platzieren, und der Benutzer sieht nur Ihre Webseite und denkt, dass er auf IHRE Schaltflächen klickt.

0 Stimmen

Die Warnmeldung würde immer noch angezeigt werden, aber es ist natürlich einfach, den Link zur sicheren Seite zu verbergen, wie Sie vorschlagen. Aber warum sollte ich mir die Mühe machen, meine Seite umzugestalten, um die Leute dazu zu bringen, auf eine bekannte Schaltfläche zu klicken, wenn man die Seite einfach kopieren und den gleichen Effekt erzielen kann? Der obige Code verhindert hauptsächlich Clickjacking. Wenn Sie meine Seite unsichtbar über einer anderen Seite anzeigen, ist es nicht möglich, Aktionen auf meiner Site auszulösen.

0 Stimmen

Wenn dies in einem IE8-Sperrzonen-Frame oder Chrome-Sandbox-Frame platziert wird, wird das Javascript nie ausgeführt. Ich frage mich, welche Änderungen in diesen Fällen erforderlich sind

6voto

if (top != self) {
  top.location.replace(location);
  location.replace("about:blank"); // want me framed? no way!
}

6voto

DaveRandom Punkte 85940

Ich werde mutig sein und meinen Hut in den Ring werfen (so alt er auch sein mag), mal sehen, wie viele negative Bewertungen ich sammeln kann.

Hier ist mein Versuch, der überall zu funktionieren scheint, wo ich ihn getestet habe (Chrome20, IE8 und FF14):

(function() {
    if (top == self) {
        return;
    }

    setInterval(function() {
        top.location.replace(document.location);
        setTimeout(function() {
            var xhr = new XMLHttpRequest();
            xhr.open(
                'get',
                'http://mysite.tld/page-that-takes-a-while-to-load',
                false
            );
            xhr.send(null);
        }, 0);
    }, 1);
}());

Ich habe diesen Code in der <head> und rief es vom Ende der <body> um sicherzustellen, dass meine Seite gerendert wird, bevor sie beginnt, mit dem bösartigen Code zu streiten, ich weiß nicht, ob dies der beste Ansatz ist, YMMV.

Wie funktioniert das?

...höre ich Sie fragen - die ehrliche Antwort ist, dass ich es nicht weiß. まったくもって wissen. Ich musste viel herumprobieren, damit es überall funktioniert, wo ich es getestet habe, und die genaue Wirkung variiert leicht, je nachdem, wo man es einsetzt.

Der Gedanke dahinter ist folgender:

  • Stellen Sie eine Funktion so ein, dass sie mit dem kleinstmöglichen Intervall läuft. Das Grundkonzept hinter allen realistischen Lösungen, die ich gesehen habe, besteht darin, den Scheduler mit mehr Ereignissen zu füllen, als der Frame Buster-Buster hat.
  • Jedes Mal, wenn die Funktion ausgelöst wird, versuchen Sie, die Position des oberen Rahmens zu ändern. Ziemlich offensichtliche Anforderung.
  • Planen Sie auch eine Funktion ein, die sofort ausgeführt werden soll, aber lange braucht, um abgeschlossen zu werden (dadurch wird verhindert, dass der Frame Buster-Buster die Ortsveränderung behindert). Ich habe eine synchrone XMLHttpRequest gewählt, weil es der einzige Mechanismus ist, der mir einfällt, der keine Benutzerinteraktion erfordert (oder zumindest darum bittet) und die CPU-Zeit des Benutzers nicht verschlingt.

Für meine http://mysite.tld/page-that-takes-a-while-to-load (das Ziel der XHR) habe ich ein PHP-Skript verwendet, das wie folgt aussieht:

<?php sleep(5);

Was geschieht?

  • Chrome und Firefox warten die 5 Sekunden, während die XHR abgeschlossen wird, und leiten dann erfolgreich zur URL der eingerahmten Seite um.
  • Der IE leitet so gut wie sofort um

Kann man die Wartezeit in Chrome und Firefox nicht vermeiden?

Offensichtlich nicht. Zuerst habe ich die XHR auf eine URL verwiesen, die eine 404 zurückgibt - das hat in Firefox nicht funktioniert. Dann versuchte ich die sleep(5); Ansatz, den ich schließlich für diese Antwort gewählt habe, dann habe ich angefangen, mit der Länge des Schlafs auf verschiedene Arten zu spielen. Ich konnte kein wirkliches Muster für das Verhalten finden, aber ich fand heraus, dass, wenn es zu kurz ist, speziell Firefox nicht mitspielt (Chrome und IE scheinen sich ziemlich gut zu verhalten). Ich weiß nicht, wie die Definition von "zu kurz" in Wirklichkeit lautet, aber 5 Sekunden scheint jedes Mal zu funktionieren.


Wenn irgendwelche vorbeigehenden Javascript-Ninjas ein wenig besser erklären wollen, was hier vor sich geht, warum das (wahrscheinlich) falsch ist, unzuverlässig, der schlechteste Code, den sie je gesehen haben usw., werde ich gerne zuhören.

0 Stimmen

Sieht so aus, als könnten Sie alle Ihre besorgniserregenden Sätze entfernen

5voto

Ok, wir wissen also, dass wir in einem Rahmen waren. Also verweisen wir mit location.href auf eine andere spezielle Seite mit dem Pfad als GET-Variable. Jetzt erklären wir dem Benutzer, was vor sich geht, und bieten einen Link mit der Option target="_TOP" an. Das ist einfach und würde wahrscheinlich funktionieren (ich habe es nicht getestet), aber es erfordert eine gewisse Benutzerinteraktion. Vielleicht könnten Sie den Benutzer auf die anstößige Seite hinweisen und eine Schande über die Clickjacker auf Ihrer Seite aufstellen Nur eine Idee, aber es könnte funktionieren.

4voto

D'Arcy Rittich Punkte 159655

Nun, man kann den Wert des Zählers ändern, aber das ist natürlich eine brüchige Lösung. Sie können Ihren Inhalt über AJAX laden, nachdem Sie festgestellt haben, dass sich die Website nicht innerhalb eines Frames befindet - auch keine großartige Lösung, aber es vermeidet hoffentlich das Auslösen des Ereignisses "on beforeunload" (ich nehme an).

Edit: Eine weitere Idee. Wenn du feststellst, dass du dich in einem Frame befindest, bitte den Benutzer, Javascript zu deaktivieren, bevor du auf einen Link klickst, der dich zu der gewünschten URL führt (indem du einen Querystring übergibst, der deiner Seite mitteilt, dass sie dem Benutzer sagen soll, dass er Javascript wieder aktivieren kann, sobald er dort ist).

Bearbeiten 2: Wenn Sie feststellen, dass Sie sich in einem Frame befinden, löschen Sie einfach den Inhalt Ihres Dokuments und drucken Sie eine unangenehme Nachricht aus.

Bearbeiten 3: Können Sie das oberste Dokument aufzählen und alle Funktionen auf Null setzen (auch anonyme)?

0 Stimmen

Outlook (ehemals Hotmail) wird 'nuklear', wenn es nicht aus einem Rahmen herauskommt - es setzt den gesamten Inhalt der <body> innerhalb einer <plaintext> Tag gesetzt auf display: none . Es ist ziemlich effektiv.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X