2020
Eval is Evil!

Eval is Evil!

Datum: März 2020
Lesedauer: 3 Minuten


Vor ein paar Wochen wurde ich damit beauftragt, einen Taschenrechner zu schreiben. Die grösste Schwierigkeit war das Berechnen des Resultats. Ich wendete viel Zeit auf, um den Code zu schreiben, welcher schliesslich die Berechnungen durchführt. Jedoch war das äusserst schwierig. Also begann ich zu recherchieren. Da kam ich mit eval() in Kontakt.

Was ist Eval?

eval() ist ein Funktionsaufruf, welchem man einen String als Parameter mitgeben kann. Eval berechnet nun den String und gibt das Resultat zurück. Die Funktion hat mich wirklich überzeugt, da sie auch Dingen wie z.B. der Punkt- vor Strichrechnung Beachtung schenkt.

var calculation = '2+3*5';
console.log(eval(calculation)); // 17

Evil?

Ich war wirklich erleichtert, als ich eval() entdeckte. Doch dann bin ich auf folgende Überschrift gestossen: "Never use eval()!"

Also habe ich weiter gesucht. Doch ich bin nur auf Seiten gestossen, die dasselbe behaupten.

Die Aussage "Eval is Evil" wird Douglas Crockford zugeschrieben. Dies ist ein erfolgreicher Programmierer, welcher auch bei der Entwicklung von JS involviert war. Er ist einer der Gründe, warum eval() als etwas bösartiges angesehen wird.

Darum wird eval() als etwas schlechtes dargestellt:

Verwendet man ein Eingabe Feld, wo die Rechnung eingegeben wird, so weist sich eine Sicherheitslücke auf. In diesem input Feld kann nämlich auch JS Code eingetippt werden, welcher dann möglicherweise Schaden anrichtet. Zudem erschwert es das Debugging und macht die Anwendung langsamer. Obwohl sich letzteres in den letzten Jahren um einiges verbessert hat, ist eval() immer noch sehr ineffizient.

Ich sehe ebenfalls als Nachteil, dass wenn ein anderer Datentyp mitgegeben wird, eval() einfach den exakt selben Wert zurückgibt.

Folgendes Bespiel habe ich zur Unsicherheit gefunden:

Dieser Befehl würde, laut des Verfassers, alle Files im Directory löschen, in welchem man sich befindet.

const valueFromInput = `require("child_process").exec('rm -rf ./*')`;
eval(`console.log(`User input: ${valueFromInput}`)`);

Alternative

Ich habe eine weitere, ähnliche Funktion (windows.Function()) gefunden. Jedoch weist sie die selben Probleme auf. Am besten schreibt man die Funktion selber oder benutzt eine Library.

Beispiele:

  • expression-eval
  • math.js

Auf die zwei Varianten gehe ich hier nicht weiter ein, da ich sie weder getestet, noch mich gründlich darüber informiert habe.

Will man Eval nicht ersetzen, so sollte man unerlaubte Zeichen herausfiltern, bevor man die Eingabe der Funktion als Paramter übergibt.

Fazit

eval() wird in heutzutage aufgrund ihres schlechten Schutzes und der Performance äusserst selten verwendet. Grundsätzlich muss man vermeiden, die Funktion zu nutzen. Jedoch gibt es auch Fälle, wo es sinnvoll ist, sie zu verwenden.

Schlussendlich muss aber jeder für sich selbst abschätzen, ob er von eval() gebrauch machen will. Wichtig ist einfach, dass man sich den Risiken bewusst ist.

Ich bin trotzdem froh, dass ich eval() entdeckt habe. In meinem Fall stand weder die Performance, noch die Sicherheit im Vordergrund der Übung. Ausserdem verwende ich onkeypress (und kein input Feld) um die Zeichen einzulesen. Daher habe ich die Funktion vorerst in meiner Anwendung gelassen.