W3docs

JavaScript eval()

Wie eval() in JavaScript einen string als Code ausführt: Syntax, Rückgabewert, direkte und indirekte Aufrufe, Sicherheits- und Leistungsrisiken sowie Alternativen.

JavaScript kann zur Laufzeit einen string in ausführbaren Code umwandeln. Die eingebaute Funktion eval() tut genau das: Sie nimmt einen string, behandelt ihn als JavaScript-Quellcode und führt ihn aus. Diese Seite erklärt, wie eval() funktioniert, wann sie einen Wert zurückgibt, warum sie fast immer das falsche Werkzeug ist und was stattdessen verwendet werden sollte.

Diese Seite behandelt:

  • Die Syntax von eval() und was sie zurückgibt.
  • Praktische Anwendungsfälle (und warum die meisten davon heute bessere Alternativen haben).
  • Die Sicherheits- und Leistungsprobleme, die eval() gefährlich machen.
  • Sicherere Alternativen: der Function-Konstruktor und JSON.parse().
  • Best Practices für die seltenen Fälle, in denen man eval() tatsächlich benötigt.

Die eval()-Funktion verstehen

eval() wertet einen string mit JavaScript-Code aus oder führt ihn aus. Ist der string ein Ausdruck, wertet eval() ihn aus und gibt das Ergebnis zurück. Enthält der string eine oder mehrere Anweisungen, führt eval() sie aus und gibt den Wert der letzten Ausdrucksanweisung zurück (oder undefined).

Syntax

eval(string)

Parameter:

  • string — ein string mit JavaScript-Quellcode, der ausgewertet werden soll.

Rückgabewert: das Ergebnis des zuletzt ausgewerteten Ausdrucks oder undefined, wenn der string keine Ausdrücke enthält.

Ist string kein string (z. B. eine Zahl), gibt eval() das Argument unverändert zurück.

Verwendungsbeispiel

In diesem Beispiel wird ein einfacher arithmetischer Ausdruck ausgewertet und das Ergebnis ausgegeben:

javascript— editable

Praktische Anwendungsfälle für eval()

Obwohl die Funktion eval() sehr mächtig sein kann, wird ihre Verwendung aufgrund von Sicherheits- und Leistungsproblemen oft abgeraten. Es gibt jedoch Szenarien, in denen eval() nützlich sein kann.

Dynamische Codeausführung

In Situationen, in denen Code dynamisch generiert und ausgeführt werden muss, kann eval() eine praktische Lösung sein. Zum Beispiel beim Erstellen eines Taschenrechners, der Benutzereingaben als mathematischen Ausdruck auswertet:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Dynamic Calculator</title>
</head>
<body>
    <p>Add any arithmetic expression like 12 + 5 and hit 'Calculate' button!</p>
    <div>
        <input type="text" id="expression" placeholder="Enter expression" /> <!-- User input field -->
        <button onclick="evaluateExpression()">Calculate</button> <!-- Button to trigger calculation -->
    </div>
    <div id="calcResult"></div> <!-- Element to display result -->
    <script>
        function evaluateExpression() {
            const expression = document.getElementById('expression').value; // Get user input
            try {
                const result = eval(expression); // Evaluate the expression
                document.getElementById('calcResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('calcResult').textContent = 'Invalid expression'; // Handle invalid input
            }
        }
    </script>
</body>
</html>

JSON mit eval() parsen

Vor der Einführung von JSON.parse() wurde eval() zum Parsen von JSON-strings verwendet. Aus Sicherheitsgründen wird jedoch heute die Verwendung von JSON.parse() empfohlen.

javascript— editable

Bei der Verwendung von eval() zum Parsen von JSON-strings ist es entscheidend sicherzustellen, dass der JSON-string als object-Ausdruck und nicht als Blockanweisung interpretiert wird. Dazu wird der JSON-string in Klammern eingeschlossen, bevor er an eval() übergeben wird. Dies stellt sicher, dass JavaScript den string als object-Ausdruck behandelt und Syntaxfehler vermieden werden, die entstehen könnten, wenn der string als Blockanweisung interpretiert würde.

Info

Bevorzuge immer JSON.parse() gegenüber eval() zum Parsen von JSON. JSON.parse() akzeptiert nur Daten und kann daher niemals ein eingeschleustes Skript ausführen.

Direkter vs. indirekter eval und Scope

Wie eval() Variablen sieht, hängt davon ab, wie man es aufruft.

Ein direkter Aufruf — eval(code) wörtlich geschrieben — führt den Code im aktuellen Scope aus. Er kann Variablen lesen und sogar dort erstellen, wo er aufgerufen wird:

javascript— editable

Ein indirekter Aufruf — wenn eval über eine andere Referenz als den wörtlichen Namen aufgerufen wird, z. B. (0, eval)(code) oder durch Speichern in einer Variable — führt den Code stattdessen im globalen Scope aus. Er kann keine lokalen Variablen sehen:

javascript— editable

Im Strict Mode erhält sogar ein direktes eval() seinen eigenen Scope: Variablen, die es deklariert, gelangen nicht in die umgebende Funktion. Das ist ein weiterer Grund, warum moderner Code eval() kaum noch benötigt.

Sicherheits- und Leistungsbedenken

Die Verwendung von eval() kann erhebliche Sicherheitsrisiken und Leistungsprobleme verursachen. Hier ist der Grund dafür:

Sicherheitsrisiken

eval() kann beliebigen JavaScript-Code ausführen und ist daher anfällig für Injection-Angriffe. Ein Angreifer könnte potenziell schadhaften Code einschleusen, was zu schwerwiegenden Sicherheitsverletzungen führen kann.

Beispiel für ein Sicherheitsrisiko:

Stell dir vor, du hast eine Webanwendung, die Benutzereingaben entgegennimmt und mit eval() auswertet. Ohne ordnungsgemäße Validierung kann dies von einem Angreifer ausgenutzt werden, um schadhaften Code auszuführen.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>eval() Security Risk Example</title>
</head>
<body>
    <div>
     <p>Hit 'Run Code' button!</p>
        <input type="text" id="userInput" placeholder="Enter code" value="alert('Hacked!')" /> <!-- User input field -->
        <button onclick="evaluateUserInput()">Run Code</button> <!-- Button to run code -->
    </div>
    <div id="userInputResult"></div> <!-- Element to display result -->
    <script>
        function evaluateUserInput() {
            const input = document.getElementById('userInput').value; // Get user input
            try {
                const result = eval(input); // Evaluate the user input
                document.getElementById('userInputResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('userInputResult').textContent = 'Error in evaluation'; // Handle evaluation error
            }
        }
    </script>
</body>
</html>

In diesem Beispiel führt eval() eine Eingabe wie alert('Hacked!') aus und verursacht damit eine Sicherheitsverletzung durch Anzeige eines Alert-Fensters. Ein Angreifer könnte schädlicheren Code einschleusen und potenziell das gesamte System kompromittieren.

Leistungsprobleme

eval() führt Code im selben Scope aus, von dem aus es aufgerufen wird, und verhindert damit bestimmte Optimierungen der JavaScript-Engine. Dies kann im Vergleich zu anderen Ansätzen zu langsamerer Leistung führen.

Beispiel für ein Leistungsproblem:

Betrachten wir ein Szenario, in dem wir eine Reihe von Berechnungen mehrfach durchführen müssen. Die Verwendung von eval() für diese Aufgabe kann die Leistung erheblich beeinträchtigen.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Performance Issues with eval()</title>
</head>
<body>
    <div id="evalResult"></div>
    <div id="functionResult"></div>
    <script>
        // Using eval()
        const evalStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            eval("3 * 4 + 5");
        }
        const evalEndTime = performance.now();
        const evalDuration = evalEndTime - evalStartTime;
        document.getElementById('evalResult').textContent = `Time taken with eval(): ${evalDuration} ms`;

        // Using Function constructor
        const func = new Function('return 3 * 4 + 5');
        const funcStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            func();
        }
        const funcEndTime = performance.now();
        const funcDuration = funcEndTime - funcStartTime;
        document.getElementById('functionResult').textContent = `Time taken with Function constructor: ${funcDuration} ms`;
    </script>
</body>
</html>

In diesem Beispiel vergleichen wir die Leistung von eval() mit dem Function-Konstruktor. Wir führen eine einfache arithmetische Operation (3 * 4 + 5) 100.000 Mal mit beiden Methoden aus und messen die jeweilige Dauer.

  • Mit eval(): Der Code innerhalb von eval() wird wiederholt ausgewertet, was langsamer ist, da bestimmte Optimierungen verhindert werden.
  • Mit dem Function-Konstruktor: Der Function-Konstruktor erstellt eine Funktion, die dieselbe Operation ausführt, aber schneller ist, da er JavaScript-Engines erlaubt, die wiederholte Ausführung zu optimieren.

Die auf der Webseite angezeigten Ergebnisse zeigen die von jeder Methode benötigte Zeit und demonstrieren, dass eval() aufgrund seiner Leistungsprobleme langsamer ist.

Warnung

Vermeide eval(), es sei denn, es ist absolut notwendig. Greife zuerst auf sicherere Alternativen zurück: den Function-Konstruktor für dynamische Funktionen oder JSON.parse() für Daten.

Alternativen zu eval()

Für eine sicherere und effizientere Codeausführung sollten folgende Alternativen in Betracht gezogen werden:

Verwendung des Function-Konstruktors

Der Function-Konstruktor erstellt ein neues Funktionsobjekt, ähnlich wie eval(), aber mit besserer Sicherheit und Leistung.

javascript— editable

Verwendung von JSON.parse()

Zum Parsen von JSON-strings ist JSON.parse() die bevorzugte Methode.

javascript— editable

Best Practices für die Verwendung von eval()

Wenn eval() unbedingt verwendet werden muss, sollten diese Best Practices befolgt werden, um Risiken zu minimieren:

1. Eingaben validieren

Stelle sicher, dass die Eingabe für eval() streng validiert wird, um Code-Injection zu verhindern. Das bedeutet, nur sichere Zeichen und Ausdrücke zuzulassen.

Beispiel:

javascript— editable

In diesem Beispiel wird ein regulärer Ausdruck verwendet, um die Benutzereingabe zu validieren. Nur numerische Zeichen und grundlegende arithmetische Operatoren sind erlaubt. Stimmt die Eingabe mit dem Muster überein, wird sie mit eval() ausgewertet. Andernfalls wird sie als ungültig abgelehnt.

2. Try-Catch verwenden

Umschließe eval() mit einem Try-Catch-Block, um potenzielle Fehler elegant zu behandeln. Dies verhindert, dass die gesamte Anwendung abstürzt, wenn eval() auf einen Fehler trifft.

Beispiel:

javascript— editable

Hier werden Syntaxfehler in der Benutzereingabe mit einem Try-Catch-Block behandelt. Wirft eval() einen Fehler, wird er abgefangen und eine Fehlermeldung ausgegeben, anstatt die Anwendung zum Absturz zu bringen.

3. Scope einschränken

Minimiere den Scope der für eval() zugänglichen Variablen, um potenzielle Schäden durch schadhaften Code zu begrenzen. Verwende einen sofort aufgerufenen Funktionsausdruck (IIFE), um einen lokalen Scope zu erstellen.

Beispiel:

javascript— editable

In diesem Beispiel wird eine Funktion restrictedEval innerhalb eines IIFE definiert, um einen lokalen Scope zu erstellen. Diese Funktion wertet die Eingabe mit eval() aus, aber mit lokal definierten Variablen a und b. Die globalen Variablen a und b sind nicht zugänglich, was die Scope-Einschränkung demonstriert.

Durch die Einhaltung dieser Best Practices können die mit der Verwendung von eval() verbundenen Risiken verringert werden, während seine dynamischen Codeausführungsfähigkeiten bei Bedarf weiterhin genutzt werden können.

Fazit

Die Funktion eval() in JavaScript bietet ein mächtiges Werkzeug für die dynamische Codeausführung, ist aber mit erheblichen Risiken und Leistungsnachteilen verbunden. In der Praxis gibt es für fast jede Aufgabe, die eval() zu erfordern scheint, eine sicherere Lösung: Verwende JSON.parse() für Daten, den Function-Konstruktor für dynamische Funktionen und object-/array-Lookups anstelle von aus strings zusammengesetzten Variablennamen. Musst du eval() verwenden, validiere die Eingaben, umschließe es mit try...catch und halte seinen Scope so klein wie möglich.

Verwandte Themen

Übungen

Übung
Was macht die eval()-Funktion in JavaScript?
Was macht die eval()-Funktion in JavaScript?
Was this page helpful?