© saicle/Shutterstock.com
Kolumne: The Good Parts

Kolumne: The Good Parts


JavaScript ist eine äußerst flexible sowie dynamische Sprache. Es ist möglich, nahezu jeden Bestandteil der Laufzeitumgebung zu verändern oder zu überschreiben. Es ist ein Leichtes, Funktionen (z. B. String.prototype.indexOf) zu überschreiben und den Programmablauf somit grundlegend zu beeinflussen. Auch wenn das Manipulieren von Funktionen, die zur Standard-Library gehören, als schlechter Stil gilt, ist es dennoch möglich. Besonders bei der Entwicklung von Bibliotheken, deren Ziel der Einsatz in unterschiedlichsten Websites und Applikationen ist, sollte diese Gefahr bedacht werden.

Um eine Lösung für dieses Problem zu entwerfen, muss es zunächst genau betrachtet werden. Listing 1 zeigt ein kleines Programm, das JavaScripts interne Array-Funktionen push und pop einsetzt, um die Ausgabe eines Strings in die Konsole zu steuern. Das Programm funktioniert wie erwartet und speichert mit jedem Aufruf von queueString die ihr übergebene Zeichenkette ab. Ein Aufruf von printOutput gibt diese Zeichenketten schließlich in umgekehrter Reihenfolge aus.

Listing 1

var queueOutput, printOutput; (function() { var queue = []; queueOutput = function(output) { queue.push(function() { console.log(output); }); }; printOutput = function() { var outputFn; while (outputFn = queue.pop()) { outputFn(); } }; }()); queueOutput("Output"); queueOutput("Some"); printOutput(); // >> Some // >> Output

Das Programm funktioniert, weil die Laufzeitumgebung push und pop wie erwartet auf dem Array-Prototypen zur Verfügung stellt. Ein Überschreiben der Array.prototype.push-Funktion würde es einen Angreifer z. B. ermöglichen, in diesem Beispiel beliebigen Code auszuführen. Listing 2 zeigt hierfür ein Beispiel. JavaScripts Konzept der prototypischen Programmierung ermöglicht es hier, nachträglich den Array-Prototypen zu verändern und auf diesem Wege in den Ablauf der Ausführung einzugreifen.

Listing 2

printOutput(); (function() { var _push = Array.prototype.push; Array.prototype.push = function(entry) { _push.call(this, function() { console.log("INJECTED CODE!"); }); }; }()); queueOutput("Some queued Output"); printOutput(); // >> INJECTED CODE!

Die Lösung

Die naheliegendste Lösung des skizzierten Problems ist die Sicherung aller benötigten Funktionen aus der Laufzeitumgebung im Scope der eigenen Bibliothek. Mittels der beiden Funktionen bind und call kann eben jene Aufgabe gelöst werden. Der erste Schritt ist es, sicherzustellen, dass die Funktion bind gesichert ist und nachträglich nicht mehr...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang