it-swarm-eu.dev

Warum ist die Verwendung der JavaScript-Auswertungsfunktion eine schlechte Idee?

Die Eval-Funktion ist eine leistungsstarke und einfache Möglichkeit, Code dynamisch zu generieren. Was sind die Einschränkungen?

512
Brian Singh
  1. Die unsachgemäße Verwendung von eval öffnet Ihren Code für Injektionsangriffe

  2. Debugging kann schwieriger sein (keine Zeilennummern usw.)

  3. evaluierter Code wird langsamer ausgeführt (keine Möglichkeit, evaluierten Code zu kompilieren/zwischenzuspeichern)

Bearbeiten: Wie @Jeff Walden in den Kommentaren ausführt, ist # 3 heute weniger wahr als 2008. Während es jedoch zu Zwischenspeichern von kompilierten Skripten kommen kann, ist dies nur auf Skripten beschränkt, die ohne Änderung wiederholt werden. Ein wahrscheinlicheres Szenario ist, dass Sie Skripts auswerten, die jedes Mal geringfügig geändert wurden und daher nicht zwischengespeichert werden konnten. Sagen wir einfach, dass SOME eval'd code langsamer ausgeführt wird.

374
Prestaul

eval ist nicht immer böse Es gibt Zeiten, in denen es vollkommen angemessen ist.

Allerdings wird eval derzeit und historisch massiv von Leuten überbeansprucht, die nicht wissen, was sie tun. Das schließt leider auch Leute ein, die JavaScript-Tutorials schreiben, und in einigen Fällen kann dies tatsächlich Sicherheitsfolgen haben - oder häufiger einfache Fehler. Je mehr wir also tun können, um ein Fragezeichen über eval zu setzen, desto besser. Jedes Mal, wenn Sie eval verwenden, müssen Sie überprüfen, was Sie tun, denn es besteht die Möglichkeit, dass Sie es auf eine bessere, sicherere und sauberere Weise tun.

Um ein allzu typisches Beispiel zu geben, legen Sie die Farbe eines Elements mit einer ID fest, die in der Variablen 'potato' gespeichert ist:

eval('document.' + potato + '.style.color = "red"');

Wenn die Autoren der oben genannten Art von Code eine Ahnung von den Grundlagen der Funktionsweise von JavaScript-Objekten hätten, hätten sie erkannt, dass anstelle von wörtlichen Punktnamen auch eckige Klammern verwendet werden können, wodurch die Notwendigkeit einer Auswertung entfällt:

document[potato].style.color = 'red';

... was viel einfacher zu lesen und weniger fehleranfällig ist.

(Aber dann würde jemand, der/wirklich/wusste, was er tut, sagen:

document.getElementById(potato).style.color = 'red';

dies ist zuverlässiger als der zweifelhafte alte Trick, direkt aus dem Dokumentobjekt heraus auf DOM-Elemente zuzugreifen.)

342
bobince

Ich glaube, es liegt daran, dass es jede JavaScript-Funktion aus einer Zeichenfolge ausführen kann. Durch die Verwendung wird es für Benutzer einfacher, unerwünschten Code in die Anwendung einzufügen.

37
kemiller2002

Zwei Punkte fallen mir ein:

  1. Sicherheit (solange Sie die zu bewertende Zeichenfolge jedoch selbst generieren, ist dies möglicherweise kein Problem.)

  2. Leistung: Solange der auszuführende Code nicht bekannt ist, kann er nicht optimiert werden. (über Javascript und Leistung, sicherlich Steve Yegges Präsentation )

26
xtofl

Das Übergeben von Benutzereingaben an eval () ist ein Sicherheitsrisiko, aber auch jeder Aufruf von eval () erstellt eine neue Instanz des JavaScript-Interpreters. Dies kann ein Ressourcenfresser sein.

20
Andrew Hedges

Dies ist in der Regel nur dann ein Problem, wenn Sie eine Bewertung der Benutzereingaben vornehmen.

18
Mark Biek

Hauptsächlich ist es viel schwieriger zu warten und zu debuggen. Es ist wie ein goto. Sie können es verwenden, aber es macht es schwieriger, Probleme zu finden, und es ist schwieriger für die Leute, die möglicherweise später Änderungen vornehmen müssen.

15
Brian

Beachten Sie, dass Sie eval () häufig verwenden können, um Code in einer ansonsten eingeschränkten Umgebung auszuführen. Websites in sozialen Netzwerken, die bestimmte JavaScript-Funktionen blockieren, können manchmal getäuscht werden, indem sie in einem Auswertungsblock getrennt werden.

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Wenn Sie also einen JavaScript-Code ausführen möchten, der ansonsten möglicherweise nicht zulässig ist ( Myspace , ich sehe Sie an ...), kann eval () ein nützlicher Trick sein.

Aus den oben genannten Gründen sollten Sie es jedoch nicht für Ihren eigenen Code verwenden, bei dem Sie die vollständige Kontrolle haben - es ist nur nicht erforderlich und besser dran, in das Regal der "kniffligen JavaScript-Hacks" abzusteigen.

13
matt lohkamp

Es sei denn, Sie lassen eval () einen dynamischen Inhalt (über CGI oder Eingabe) zu, ist dieser so sicher und solide wie alle anderen JavaScript-Elemente auf Ihrer Seite.

11
Thevs

Zusammen mit dem Rest der Antworten glaube ich nicht, dass eval-Aussagen eine fortgeschrittene Minimierung haben können.

7
Paul Mendoza

Dies ist ein mögliches Sicherheitsrisiko, hat einen anderen Ausführungsumfang und ist recht ineffizient, da eine völlig neue Skriptumgebung für die Ausführung des Codes erstellt wird. Weitere Informationen finden Sie hier: eval .

Es ist jedoch sehr nützlich und kann mit Moderation eine Menge guter Funktionen hinzufügen.

6
Tom

Ich weiß, dass diese Diskussion alt ist, aber ich mag this Ansatz von Google und wollte dieses Gefühl mit anderen teilen;)

Die andere Sache ist, dass je besser du wirst, desto mehr versuchst du zu verstehen und schließlich glaubst du einfach nicht, dass etwas gut oder schlecht ist, nur weil es jemand gesagt hat :) Dies ist ein sehr inspirierendes Video das hat mir geholfen, mehr über mich selbst nachzudenken :) GUTE PRAKTIKEN sind gut, aber benutze sie nicht sinnlos :)

5
op1ekun

Wenn Sie nicht zu 100% sicher sind, dass der zu bewertende Code von einer vertrauenswürdigen Quelle stammt (normalerweise von Ihrer eigenen Anwendung), ist dies eine todsichere Möglichkeit, Ihr System einem Cross-Site-Scripting-Angriff auszusetzen.

5
John Topley

Es ist nicht unbedingt so schlimm, vorausgesetzt Sie wissen, in welchem ​​Kontext Sie es verwenden.

Wenn Ihre Anwendung eval() verwendet, um ein Objekt aus einem JSON-Code zu erstellen, der von einem XMLHttpRequest auf Ihre eigene Site zurückgekehrt ist und von Ihrem vertrauenswürdigen serverseitigen Code erstellt wurde, ist dies wahrscheinlich nicht der Fall ein Problem.

Nicht vertrauenswürdiger clientseitiger JavaScript-Code kann sowieso nicht so viel. Vorausgesetzt, das Ding, auf dem Sie eval() ausführen, stammt aus einer vernünftigen Quelle, ist alles in Ordnung.

5
MarkR

Dies verringert Ihr Vertrauen in die Sicherheit erheblich.

4
David Plumpton

Wenn Sie möchten, dass der Benutzer einige logische Funktionen eingibt und nach UND OR) auswertet, ist die JavaScript-Bewertungsfunktion perfekt. Ich kann zwei Zeichenfolgen und eval(uate) string1 === string2 usw. akzeptieren.

4
Ian

Wenn Sie die Verwendung von eval () in Ihrem Code bemerken, denken Sie daran, dass das Mantra „eval () ist böse“ lautet.

Diese Funktion verwendet eine beliebige Zeichenfolge und führt sie als JavaScript-Code aus. Wenn der betreffende Code im Voraus bekannt ist (zur Laufzeit nicht bestimmt), gibt es keinen Grund, eval () zu verwenden. Wenn der Code zur Laufzeit dynamisch generiert wird, gibt es oft eine bessere Möglichkeit, das Ziel ohne eval () zu erreichen. Beispielsweise ist die Verwendung der eckigen Klammer für den Zugriff auf dynamische Eigenschaften besser und einfacher:

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

Die Verwendung von eval() hat auch Auswirkungen auf die Sicherheit, da Sie möglicherweise Code ausführen (z. B. aus dem Netzwerk), der manipuliert wurde. Dies ist ein gängiges Antimuster bei der Verarbeitung einer JSON-Antwort auf eine Ajax-Anfrage. In diesen Fällen ist es besser, die in den Browsern integrierten Methoden zu verwenden, um die JSON-Antwort zu analysieren und sicherzustellen, dass sie sicher und gültig ist. Für Browser, die JSON.parse() nicht unterstützen, können Sie eine Bibliothek von JSON.org verwenden.

Es ist auch wichtig, sich daran zu erinnern, dass das Übergeben von Zeichenfolgen an setInterval(), setTimeout() und den Konstruktor Function() zum größten Teil der Verwendung von eval() ähnelt und daher sollte vermieden werden.

Hinter den Kulissen muss JavaScript den als Programmcode übergebenen String noch auswerten und ausführen:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

Die Verwendung des neuen Function () -Konstruktors ähnelt eval () und sollte mit Vorsicht angegangen werden. Es könnte ein mächtiges Konstrukt sein, wird aber oft missbraucht. Wenn Sie unbedingt eval() verwenden müssen, können Sie stattdessen new Function () verwenden.

Ein kleiner potenzieller Vorteil besteht darin, dass der in new Function () ausgewertete Code in einem lokalen Funktionsbereich ausgeführt wird, sodass alle Variablen, die im ausgewerteten Code mit var definiert sind, nicht automatisch zu globalen Variablen werden.

Eine andere Möglichkeit, automatische Globals zu verhindern, besteht darin, den eval() - Aufruf in eine Sofortfunktion zu verpacken.

3
12345678

Neben den möglichen Sicherheitsproblemen beim Ausführen von vom Benutzer übermitteltem Code gibt es meistens eine bessere Möglichkeit, den Code nicht jedes Mal neu zu analysieren, wenn er ausgeführt wird. Anonyme Funktionen oder Objekteigenschaften können die meisten Verwendungen von eval ersetzen und sind viel sicherer und schneller.

2
Matthew Crumley

Dies kann zu einem größeren Problem werden, da die nächste Generation von Browsern eine gewisse Note eines JavaScript-Compilers aufweist. Über Eval ausgeführter Code funktioniert möglicherweise nicht so gut wie der Rest Ihres JavaScript mit diesen neueren Browsern. Jemand sollte ein Profil erstellen.

2
Brian

eval () ist sehr mächtig und kann verwendet werden, um eine JS-Anweisung auszuführen oder einen Ausdruck auszuwerten. Die Frage bezieht sich jedoch nicht auf die Verwendung von eval (), sondern lässt sich nur sagen, wie die Zeichenfolge, die Sie mit eval () ausführen, von einer böswilligen Partei beeinflusst wird. Am Ende führen Sie bösartigen Code aus. Mit der Macht geht eine große Verantwortung einher. Verwenden Sie es also mit Bedacht, wenn Sie es verwenden. Dies hat nicht viel mit der eval () -Funktion zu tun, aber dieser Artikel enthält ziemlich gute Informationen: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Wenn Sie suchen Die Grundlagen von eval () finden Sie hier: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

2
Phi

Dies ist einer der guten Artikel über Eval und wie es nicht böse ist: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Ich sage nicht, dass Sie sofort eval () überall einsetzen sollten. Tatsächlich gibt es nur sehr wenige gute Anwendungsfälle für die Ausführung von eval (). Es gibt definitiv Bedenken hinsichtlich der Klarheit des Codes, der Debugfähigkeit und der Leistung, die nicht übersehen werden sollten. Sie sollten jedoch keine Angst haben, es zu verwenden, wenn Sie einen Fall haben, in dem eval () sinnvoll ist. Versuchen Sie, es nicht zuerst zu verwenden, aber lassen Sie sich nicht von jemandem erschrecken, der denkt, Ihr Code sei fragiler oder weniger sicher, wenn eval () richtig verwendet wird.

2
Amr Elgarhy

Es ist nicht immer eine schlechte Idee. Nehmen wir zum Beispiel die Codegenerierung. Ich habe kürzlich eine Bibliothek namens Hyperbars geschrieben, die die Lücke zwischen virtual-dom und handlebars schließt. Dazu wird eine Lenker-Vorlage analysiert und in Hyperskript konvertiert, das anschließend von virtual-dom verwendet wird. Das Hyperskript wird zuerst als Zeichenfolge generiert und bevor es zurückgegeben wird, eval(), um es in ausführbaren Code umzuwandeln. Ich habe eval() in dieser besonderen Situation das genaue Gegenteil des Bösen gefunden.

Grundsätzlich aus

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

Dazu

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

Die Leistung von eval() ist in einer solchen Situation kein Problem, da Sie die generierte Zeichenfolge nur einmal interpretieren und die ausführbare Ausgabe dann mehrmals verwenden müssen.

Sie können sehen, wie die Code-Generierung erreicht wurde, wenn Sie neugierig sind hier .

1
Wikened

Ich werde nicht versuchen, das bisher Gesagte zu widerlegen, aber ich werde diese Verwendung von eval () anbieten, die (soweit ich weiß) auf keine andere Weise möglich ist. Es gibt wahrscheinlich andere Möglichkeiten, dies zu codieren und möglicherweise zu optimieren, aber dies erfolgt aus Gründen der Klarheit in langwierigen Schritten und ohne Schnickschnack, um die Verwendung von eval zu veranschaulichen, für die es wirklich keine anderen Alternativen gibt. Das heißt: dynamisch (oder genauer) programmgesteuert erstellte Objektnamen (im Gegensatz zu Werten).

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

BEARBEITEN: Übrigens würde ich nicht vorschlagen (aus den oben genannten Sicherheitsgründen), dass Sie Ihre Objektnamen auf Benutzereingaben basieren. Ich kann mir keinen guten Grund vorstellen, warum du das tun möchtest. Trotzdem dachte ich, ich würde darauf hinweisen, dass es keine gute Idee wäre :)

1
Carnix

Ich würde sogar sagen, dass es keine Rolle spielt, ob Sie eval() in Javascript verwenden, das in Browsern ausgeführt wird. * (Einschränkung)

Alle modernen Browser verfügen über eine Entwicklerkonsole, auf der Sie ohnehin beliebiges Javascript ausführen können, und jeder semi-intelligente Entwickler kann sich Ihre JS-Quelle ansehen und die benötigten Teile in die Entwicklerkonsole einfügen, um das zu tun, was er möchte.

* Solange Ihre Server-Endpunkte die korrekte Validierung und Bereinigung der vom Benutzer angegebenen Werte aufweisen, sollte es keine Rolle spielen, was in Ihrem clientseitigen Javascript analysiert und ausgewertet wird.

Wenn Sie fragen, ob es geeignet ist, eval() in PHP zu verwenden, lautet die Antwort jedoch NO =, außer Sie Whitelist Werte, die an Ihre eval-Anweisung übergeben werden können.

1
Adam Copley

Die JavaScript-Engine verfügt über eine Reihe von Leistungsoptimierungen, die während der Kompilierungsphase durchgeführt werden. Einige davon führen dazu, dass der Code während der Ausführung im Wesentlichen statisch analysiert und die Position aller Variablen- und Funktionsdeklarationen im Voraus festgelegt werden kann, sodass die Auflösung von Bezeichnern während der Ausführung weniger aufwändig ist.

Wenn die Engine jedoch eine Auswertung (..) im Code findet, muss sie im Wesentlichen davon ausgehen, dass die gesamte Kenntnis der Position des Bezeichners ungültig ist, da sie zum Zeitpunkt des Lexing nicht genau wissen kann, welchen Code Sie eval (..) übergeben können. Ändern des lexikalischen Bereichs oder des Inhalts des Objekts, an das Sie möglicherweise übergeben, um einen neuen zu konsultierenden lexikalischen Bereich zu erstellen.

Mit anderen Worten, im pessimistischen Sinne sind die meisten Optimierungen, die es machen würde, sinnlos, wenn eval (..) vorhanden ist, so dass es die Optimierungen überhaupt nicht ausführt.

Das erklärt alles.

Referenz :

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

1
hkasera

Garbage collection

Die Speicherbereinigung des Browsers hat keine Ahnung, ob der ausgewertete Code aus dem Speicher entfernt werden kann, sodass er nur so lange gespeichert bleibt, bis die Seite erneut geladen wird. Nicht schlecht, wenn Ihre Benutzer nur in Kürze auf Ihrer Seite sind, aber es kann ein Problem für die Webanwendungen sein.

Hier ist ein Skript, um das Problem zu demonstrieren

https://jsfiddle.net/CynderRnAsh/qux1osnw/

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

Etwas so Einfaches wie der obige Code bewirkt, dass eine kleine Menge an Speicher gespeichert wird, bis die App stirbt. Dies ist schlimmer, wenn das evaluierte Skript eine Riesenfunktion ist und das Intervall aufgerufen wird.

0
J D