Vorwort: Apropos Sandboxen: Wir denken vielleicht reflexartig an das obige Bild und sind sofort interessiert, aber leider geht es in diesem Artikel nicht um „Minecraft“ (eine alte Cover-Party). Der folgende Artikel wird schrittweise die Sandbox von „Browser World“ vorstellen. 1. Was ist eine Sandbox? In der Computersicherheit ist eine Die folgenden Szenarios beinhalten beispielsweise das abstrakte Konzept einer Sandbox:
2. Was sind die Anwendungsszenarien von Sandbox?Oben werden einige relativ makroökonomische Sandbox-Szenarien vorgestellt. Tatsächlich gibt es in der täglichen Entwicklung viele Szenarien, die die Anwendung eines solchen Mechanismus erfordern:
Kurz gesagt, solange wir auf nicht vertrauenswürdigen Code von Drittanbietern stoßen, können wir eine Sandbox verwenden, um den Code zu isolieren und so den stabilen Betrieb externer Programme sicherzustellen. Wenn nicht vertrauenswürdiger Code ohne jegliche Verarbeitung ausgeführt wird, besteht die offensichtlichste Nebenwirkung/der offensichtlichste Schaden im Front-End in der Verschmutzung und Manipulation des globalen // Unteranwendungscode window.location.href = 'www.diaoyu.com' Objekt.prototype.toString = () => { console.log('Du bist ein Narr :)') } document.querySelectorAll('div').fürEach(node => node.classList.add('hhh')) sendRequest(document.cookie) ... 3. So implementieren Sie eine JS-SandboxUm eine Sandbox zu implementieren, muss eigentlich ein Mechanismus zur Programmausführung entwickelt werden. Unter der Wirkung dieses Mechanismus hat die Ausführung des Programms innerhalb der Sandbox keinen Einfluss auf die Ausführung des externen Programms. 3.1 Die einfachste SandboxUm diesen Effekt zu erzielen, besteht die direkteste Idee darin, dass alle im Programm aufgerufenen Variablen aus einer zuverlässigen oder autonomen Kontextumgebung stammen, anstatt Werte aus der globalen Ausführungsumgebung zu übernehmen. Um dann zu erreichen, dass auf alle Variablen aus einer zuverlässigen Kontextumgebung zugegriffen wird, Wir müssen einen Rahmen für die Ausführung des Programms konstruieren: //Ausführungskontextobjekt const ctx = Funktion: Variable => { console.log(Variable) }, foo: "foo" } // Die einfachste Sandbox-Funktion poorestSandbox(code, ctx) { eval(code) // konstruiert einen Funktionsumfang zur Ausführung des Programms} // Auszuführendes Programm const code = ` ctx.foo = "Leiste" ctx.func(ctx.foo) ` poorestSandbox(Code, CTX) // Balken Eine solche Sandbox erfordert, dass das Quellprogramm beim Abrufen einer beliebigen Variable das Präfix des Ausführungskontextobjekts hinzufügt, was offensichtlich sehr unvernünftig ist, da wir keine Möglichkeit haben, das Verhalten Dritter zu kontrollieren. Gibt es eine Möglichkeit, dieses Präfix zu entfernen? 3.2 Eine sehr einfache Sandbox (Mit) Mithilfe der //Ausführungskontextobjekt const ctx = { Funktion: Variable => { console.log(Variable) }, foo: "foo" } // Sehr schlechte Sandbox-Funktion veryPoorSandbox(code, ctx) { mit(ctx) { // Hinzufügen mit eval(Code) } } // Auszuführendes Programm const code = ` foo = "Leiste" Funktion(foo) ` veryPoorSandbox(Code, ctx) // Balken Dadurch wird erreicht, dass nach Variablen im ausgeführten Programm im Kontext gesucht wird, der von der Sandbox bereitgestellt wird, bevor in der externen Ausführungsumgebung nach Variablen gesucht wird. Das Problem besteht darin, dass der Code, wenn eine Variable im bereitgestellten Kontextobjekt nicht gefunden wird, trotzdem die Bereichskette Schicht für Schicht durchsucht. Eine solche Sandbox kann die Ausführung des internen Codes immer noch nicht steuern. Wir möchten, dass der Code in der Sandbox nur nach Variablen im manuell bereitgestellten Kontextobjekt sucht und einen Fehler meldet oder 3.3 Nicht ganz so einfache Sandbox (mit + Proxy) Um die oben genannten Probleme zu lösen, verwenden wir eine neue Funktion von Die Get- und Set-Methoden in Da has alle Variablenzugriffe im // Erstelle ein with, um den auszuführenden Code zu umschließen und gib eine Funktionsinstanz des with-Codeblocks zurück function withedYourCode(code) { Code = 'mit(globalObj) {' + Code + '}' gibt neue Funktion zurück('globalObj', Code) } // Whitelist der globalen Bereiche, auf die zugegriffen werden kann const access_white_list = ['Math', 'Date'] // Auszuführendes Programm const code = ` Math.random() Standort.href = "xxx" Funktion(foo) ` //Ausführungskontextobjekt const ctx = { Funktion: Variable => { console.log(Variable) }, foo: "foo" } // Proxy-Objekt des Ausführungskontextobjekts const ctxProxy = new Proxy(ctx, { has: (target, prop) => { // has kann den Zugriff auf jede Eigenschaft im with-Codeblock abfangen if (access_white_list.includes(prop)) { // In der zugänglichen Whitelist kann weiter nach oben gesucht werden return target.hasOwnProperty(prop) } wenn (!target.hasOwnProperty(prop)) { throw new Error(`Ungültiger Ausdruck – ${prop}! Das kannst du nicht machen!`) } returniere wahr } }) // Nicht so arme Sandbox-Funktion littlePoorSandbox(code, ctx) { withedYourCode(code).call(ctx, ctx) // verweisen Sie dies auf das manuell erstellte globale Proxy-Objekt} littlePoorSandbox(Code, ctxProxy) // Nicht abgefangener Fehler: Ungültiger Ausdruck - Standort! Das kannst du nicht machen! An diesem Punkt können viele relativ einfache Szenarien abgedeckt werden ( Dies führt zu einer weiteren Frage: Wie kann man die Subroutine alle globalen Objekte verwenden lassen, ohne den externen globalen Status zu beeinflussen? 3.4 Natürliche, hochwertige Sandbox (iframe) Als ich die obige Frage hörte, nannte ich mich sofort einen Experten. Stellen Sie sich ein Szenario wie dieses vor: Auf einer Seite gibt es mehrere Sandbox-Fenster, von denen eines einige globale Zustände mit der Hauptseite teilen muss (z. B.: wenn Sie auf die Zurück-Schaltfläche des Browsers klicken, kehrt auch die untergeordnete Anwendung zur vorherigen Ebene zurück) und eine andere Sandbox muss einige andere globale Zustände mit der Hauptseite teilen (z. B.: Cookie-Anmeldezustand teilen). Obwohl der Browser 3.5 sollte die Sandbox nutzen können (Mit + Proxy + iframe)Um das obige Szenario zu erreichen, können wir die oben genannten Methoden zusammenfügen:
//Sandbox globale Proxy-Objektklasse class SandboxGlobalProxy { Konstruktor(gemeinsamerZustand) { // Ein Iframe-Objekt erstellen und das native globale Browserobjekt als globales Objekt der Sandbox herausnehmen const iframe = document.createElement('iframe', {url: 'about:blank'}) Dokument.Body.AnhängenUntergeordnetesElement(iframe) const sandboxGlobal = iframe.contentWindow // Globales Objekt der Sandbox-Laufzeit return new Proxy(sandboxGlobal, { has: (target, prop) => { // has kann den Zugriff auf jede Eigenschaft im with-Codeblock abfangen if (sharedState.includes(prop)) { // Wenn die Eigenschaft im gemeinsam genutzten globalen Status vorhanden ist, lass es die äußere Schicht entlang der Prototypenkette durchsuchen return false } wenn (!target.hasOwnProperty(prop)) { throw new Error(`Ungültiger Ausdruck – ${prop}! Das kannst du nicht machen!`) } returniere wahr } }) } } Funktion vielleichtVerfügbareSandbox(Code, ctx) { mit IhremCode(Code).call(ctx, ctx) } const code_1 = ` console.log(Verlauf == Fenster.Verlauf) // false fenster.abc = "Sandbox" Objekt.prototype.toString = () => { console.log('Gefangen!') } konsole.log(window.abc) // Sandbox ` const sharedGlobal_1 = ['history'] // Globales Objekt, das Sie mit der externen Ausführungsumgebung teilen möchten const globalProxy_1 = new SandboxGlobalProxy(sharedGlobal_1) vielleichtVerfügbareSandbox(code_1, globalProxy_1) window.abc // undefiniert Object.prototype.toString() // [Objekt Object] druckt nicht Traped Anhand der Ergebnisse des Beispielcodes können wir erkennen, dass wir durch die Nutzung der Vorteile der natürlichen Umgebungsisolierung von 3.6 Sandbox-FluchtSandbox ist eine Sicherheitsstrategie für Autoren , kann für Benutzer jedoch eine Einschränkung darstellen. Kreative Entwickler versuchen auf verschiedene Weise diese Einschränkung zu beseitigen, was auch als Sandbox Escape bezeichnet wird. Daher besteht die größte Herausforderung für ein Sandbox-Programm darin, diese unerwarteten Programme zu erkennen und ihre Ausführung zu verhindern. Die oben implementierte Sandbox scheint unsere Anforderungen zu erfüllen. Ist sie fertig? Tatsächlich wirken sich die folgenden Vorgänge auf die Umgebung außerhalb der Sandbox aus und ermöglichen ein Verlassen der Sandbox: Beim Zugriff auf eine interne Eigenschaft eines Objekts im Sandbox-Ausführungskontext kann // Beim Zugriff auf die Eigenschaften eines Objekts in einem Sandbox-Objekt wird ein Teil des obigen Codes ausgelassen const ctx = { Fenster: { übergeordnetes Element: {...}, ... } } Konstantencode = ` fenster.übergeordnet.abc = "xxx" ` fenster.abc // xxx
Konstantencode = ` ({}).constructor.prototype.toString = () => { console.log('Escape!') } ` ({}).toString() // Escape! Erwartet [Objekt Objekt] 3.7 „Flawless“ Sandbox (Interpreter anpassen)Bei der Implementierung einer Sandbox mit den oben genannten Methoden gibt es mehr oder weniger einige Mängel. Gibt es eine Sandbox, die fast fertig ist? Tatsächlich tun dies viele Open-Source-Bibliotheken bereits, d. h. sie analysieren die Struktur des Quellprogramms, um die Ausführungslogik jeder Anweisung manuell zu steuern. Auf diese Weise bleiben sowohl der Kontext der Angabe der Programmlaufzeit als auch die Erfassung von Vorgängen, die versuchen, der Sandbox-Steuerung zu entgehen, unter Kontrolle. Die Implementierung einer solchen Sandbox ist im Wesentlichen die Implementierung eines benutzerdefinierten Interpreters. Funktion AlmostPerfectSandbox (Code, CTX, illegalOperations) { return myInterpreter(code, ctx, illegalOperations) // benutzerdefinierter Interpreter } 4. Zusammenfassung Dieser Artikel stellt hauptsächlich die grundlegenden Konzepte und Anwendungsszenarien von Sandboxen vor und gibt Ihnen Anregungen für die Implementierung einer JavaScript-Sandbox. Die Implementierungsmethode der Sandbox ist nicht statisch und ihre Ziele sollten in Kombination mit bestimmten Szenarien analysiert werden. Darüber hinaus ist das Verhindern von Sandbox-Ausbrüchen ebenfalls eine langwierige und mühsame Aufgabe, da es schwierig ist, alle Kein Sandkasten wird über Nacht zusammengebaut, wie bei Minecraft. 5. Referenz Quellen: Quellcode: https://github.com/vuejs/vue/blob/v2.6.10/src/core/instance/proxy.js Das könnte Sie auch interessieren:
|
<<: XHTML verwendet einige veraltete Elemente in HTML nicht mehr
>>: 3 Möglichkeiten, die maximale Anzahl von Verbindungen in MySQL richtig zu ändern
CJK ist die Abkürzung für CJK Unified Ideographs,...
Um die Leistung von MySQL anzupassen und den Dien...
Der Einsatz von Containern kommt immer häufiger v...
Fehlerbeschreibung Wenn wir Docker Desktop instal...
1.17.9 Wirklich leckerer Nginx-Download-Adresse: ...
Wenn Sie MySQL installieren, wird Ihnen ein erste...
Inhaltsverzeichnis Ausgehend von der Typbeurteilu...
Sogenanntes Talent (linke und rechte Gehirnhälfte...
Inhaltsverzeichnis Vorwort Ursachenanalyse und Lö...
Inhaltsverzeichnis 1. Entdecken Sie das Problem 2...
Es gibt einige Probleme mit der komprimierten Ver...
1. CSS-Navigationsleiste (1) Funktion der Navigat...
Frage Da einige unserer Seiten Daten im Onload-Mo...
Sie können eine Funktion schreiben: Verwenden Sie...
Inhaltsverzeichnis 1. Einführung in Binlog 2. Bin...