Warum werden eval-ähnliche Merkmale im Gegensatz zu anderen möglicherweise schädlichen Merkmalen als böse angesehen?


51

Die meisten modernen Sprachen (die irgendwie interpretiert werden) haben eine Art Bewertungsfunktion . Eine solche Funktion führt einen beliebigen Sprachcode aus, der die meiste Zeit als Hauptargument als Zeichenfolge übergeben wurde (verschiedene Sprachen können der eval-Funktion weitere Funktionen hinzufügen).

Ich verstehe Benutzer sollten nicht ausgeführt werden dürfen (diese Funktion bearbeiten nehmen also direkt oder indirekt beliebige Eingabe von einem beliebigen Benutzer zu übergeben eval), vor allem mit serverseitigen Software, da sie den Prozess bösartigen Code auszuführen zwingen könnte. Auf diese Weise empfehlen uns Tutorials und Communities, eval nicht zu verwenden. Es gibt jedoch viele Male, in denen eval nützlich ist und verwendet wird:

  • Benutzerdefinierte Zugriffsregeln für Softwareelemente (IIRC OpenERP verfügt über ein Objekt, ir.ruledas dynamischen Python-Code verwenden kann).
  • Benutzerdefinierte Berechnungen und / oder Kriterien (OpenERP verfügt über solche Felder, um benutzerdefinierte Codeberechnungen zu ermöglichen).
  • OpenERP-Report-Parser (ja, ich weiß, dass ich Sie mit OpenERP-Dingen ausflippen lasse ... aber es ist das Hauptbeispiel, das ich habe).
  • Codierung von Zaubereffekten in einigen RPG-Spielen.

So haben sie eine gute Verwendung, solange sie richtig verwendet werden. Der Hauptvorteil besteht darin, dass Administratoren mit dieser Funktion benutzerdefinierten Code schreiben können, ohne weitere Dateien erstellen und einbinden zu müssen (obwohl die meisten Frameworks, die eval-Funktionen verwenden, auch die Möglichkeit haben, eine Datei, ein Modul, ein Paket usw. anzugeben, aus denen gelesen werden kann).

Eval ist jedoch in der Populärkultur böse. Dinge wie das Einbrechen in Ihr System fallen Ihnen ein.

Es gibt jedoch andere Funktionen, die bei einem Zugriff durch Benutzer schädlich sein können: Aufheben der Verknüpfung, Lesen, Schreiben (Dateisemantik), Speicherzuweisung und Zeigerarithmetik, Datenbankmodellzugriff (auch wenn SQL-injizierbare Fälle nicht berücksichtigt werden).

Im Grunde genommen ist der Code die meiste Zeit, in der ein Code nicht richtig geschrieben oder nicht richtig überwacht wird (Ressourcen, Benutzer, Umgebungen, ...), böse und kann sogar zu wirtschaftlichen Auswirkungen führen.

Aber es gibt etwas Besonderes mit evalFunktionen (unabhängig von der Sprache).

Frage : Gibt es eine historische Tatsache für diese Angst, Teil der Populärkultur zu werden, anstatt den anderen möglicherweise gefährlichen Merkmalen die gleiche Aufmerksamkeit zu widmen?


11
Ich bin nicht einverstanden, dass dies zu weit gefasst ist, und als Beweis stelle ich die vier Antworten vor, die eine angemessene Länge haben.

12
Sie stimmten als zu breit zu schließen ? (Ich kann noch keine engen Abstimmungen in dieser Community sehen.) Dieser enge Grund wird in letzter Zeit zu einem bedeutungslosen Platzhaltergrund. Besonders wenn der Punkt, den ich frage, mit Beispielen und einem spezifischen zu fragenden Punkt ziemlich klar ist. Ich werde dieses Thema in Meta fragen ...
Luis Masuelli

13
Warum wird es Teil der Populärkultur, mit mehr Aufmerksamkeit als andere gefährliche Merkmale? Weil die Alliteration eval - böse ist leicht zu merken
Bergi

5
Speicherzuweisung und Zeigerarithmetik werden von vielen als böse angesehen.
user253751

5
Es sollte beachtet werden, dass OpenERP (jetzt Odoo) nicht nur aufruft eval, sondern eine interne Funktion hat safe_eval, die die Umgebung vorbereitet, um zu verhindern, dass der Code gefährliche Dinge tut. Es wurden jedoch Fehler gefunden, da Python eine recht flexible Sprache ist und daher schwer zu kontrollieren ist.
André Paramés

Antworten:


76

Eine evalFunktion an sich ist nicht böse, und es gibt einen subtilen Punkt, von dem ich nicht glaube, dass Sie ihn machen:

Das Zulassen, dass ein Programm willkürliche Benutzereingaben ausführt, ist schlecht

Ich habe Code geschrieben, der eine evalArt von Funktion verwendete, und er war sicher: Das Programm und die Parameter waren fest codiert. Manchmal gibt es keine Sprach- oder Bibliotheksfunktion, um das zu tun, was das Programm benötigt, und die Ausführung eines Shell-Befehls ist der kurze Weg. "Ich muss das Codieren in ein paar Stunden beenden, aber das Schreiben von Java / .NET / PHP / was auch immer dauert zwei Tage. Oder ich kann evales in fünf Minuten."

Sobald Sie Benutzern erlauben, alle gewünschten Aktionen auszuführen, selbst wenn sie durch Benutzerrechte oder hinter einem "sicheren" Bildschirm gesperrt sind, erstellen Sie Angriffsmethoden. Jede Woche hat ein zufälliges CMS, eine Blog-Software usw. eine Sicherheitslücke, durch die ein Angreifer eine solche Lücke ausnutzen kann. Sie verlassen sich auf den gesamten Software-Stack, um den Zugriff auf eine Funktion zu schützen, die verwendet werden kann, rm -rf /oder auf etwas anderes Katastrophales (Hinweis: Dieser Befehl ist wahrscheinlich nicht erfolgreich, schlägt jedoch fehl, nachdem er ein bisschen Schaden angerichtet hat).

Gibt es eine historische Tatsache dafür, dass diese Angst Teil der Populärkultur wird, anstatt den anderen möglicherweise gefährlichen Merkmalen die gleiche Aufmerksamkeit zu widmen?

Ja, es gibt einen historischen Präzedenzfall. Aufgrund der zahlreichen Fehler, die im Laufe der Jahre in verschiedenen Softwareprogrammen behoben wurden, mit denen Angreifer beliebigen Code ausführen können, ist die Idee von evalmeistens in Ungnade gefallen. Moderne Sprachen und Bibliotheken verfügen über umfangreiche Funktionen, die evalweniger wichtig sind, und dies ist kein Zufall. Beides vereinfacht die Verwendung von Funktionen und verringert das Risiko eines Exploits.

Vielen potenziell unsicheren Funktionen in gängigen Sprachen wurde große Aufmerksamkeit geschenkt. Ob man mehr Aufmerksamkeit erhält, ist in erster Linie eine Ansichtssache, aber die evalFunktionen haben zweifellos ein nachweisbares Sicherheitsproblem, das leicht zu verstehen ist. Zum einen ermöglichen sie die Ausführung von Betriebssystembefehlen, einschließlich Shell-eingebauter und externer Programme, die Standard sind (z . B. rmoder del). In Kombination mit anderen Exploits kann ein Angreifer möglicherweise eine eigene ausführbare Datei oder ein eigenes Shell-Skript hochladen und über Ihre Software ausführen, wodurch fast alles passieren kann (nichts Gutes).

Das ist ein schwieriges Problem. Software ist komplex, und ein Software-Stack (z. B. LAMP ) besteht aus mehreren Softwareteilen, die auf komplexe Weise miteinander interagieren. Seien Sie vorsichtig, wie Sie Sprachfunktionen wie diese verwenden, und gestatten Sie Benutzern niemals, beliebige Befehle auszuführen.


2
Du bist der Eine :). Obwohl es ein bekanntes Beispiel gibt, das zu dieser Kultur beigetragen hat, würde ich es gerne in der Antwort sehen.
Luis Masuelli

5
Ich kenne kein einziges Beispiel, ich glaube, dies ist mehr "Tod durch tausend Schnitte" mit vielen kleineren Beispielen für Exploits, die verwendet und gepatcht werden. Ich übertreibe nicht , wenn ich sage , dass einige Remote - Exploits auf wöchentlicher Basis in gepatcht einige Stück Software.

1
Meine IDE ist ein Programm, mit dem ich - der Benutzer - willkürliche Eingaben ausführen kann. Ich finde es eher nützlich als schlecht.
Den

3
@Den das wäre eine Ausnahme. Ich bin mir sicher, dass Sie als IDE ohne diese Fähigkeit Chaos anrichten könnten. Schreiben Sie es einfach in Ihren Quellcode. Außerdem haben Sie bereits vollen Zugriff auf den Computer, auf dem es ausgeführt wird. Die Implikation hier ist, dass eine evalmöglicherweise Berechtigungen erhöhen . Das ist kein Problem, wenn sie bereits erhöht sind.

3
@Den: Das hat Raymond Chen als "die andere Seite der Luftschleuse" zusammengefasst. Sie können bereits ausführen rm -rf /, dies muss nicht auf komplizierte Weise über eine IDE erfolgen. Das Problem dabei evalist, dass es vielen Schauspielern diese Fähigkeit eröffnet, die diese Fähigkeit nicht haben sollten.
MSalters

38

Ein Teil davon ist einfach, dass Nuancen schwer sind. Es ist einfach zu sagen, dass Sie niemals goto, öffentliche Felder, String-Interpolation für SQL-Abfragen oder eval verwenden. Diese Aussagen sollten nicht so verstanden werden, als gäbe es unter keinen Umständen einen Grund, sie zu verwenden. Es ist jedoch eine gute Idee, sie als Faustregel zu vermeiden.

Von Eval wird dringend abgeraten, da es mehrere häufig auftretende Probleme kombiniert.

Erstens ist es anfällig für Injektionsattacken. Hier ist es wie bei der SQL-Injektion, dass beim Einfügen von benutzergesteuerten Daten in den Code leicht aus Versehen das Einfügen von beliebigem Code möglich ist.

Zweitens neigen Anfänger dazu, mit eval schlecht strukturierten Code zu umgehen. Ein Anfänger-Programmierer könnte Code schreiben, der so aussieht:

x0 = "hello"
x1 = "world"
x2 = "how"
x3 = "are"
x4 = "you?"
for index in range(5):
   print eval("x" + index)

Das funktioniert, ist aber wirklich der falsche Weg, um dieses Problem zu lösen. Offensichtlich wäre es viel besser, eine Liste zu verwenden.

Drittens ist eval typischerweise ineffizient. Es wird viel Mühe aufgewendet, um die Implementierung unserer Programmiersprachen zu beschleunigen. Es ist jedoch schwierig, die Bewertung zu beschleunigen, und ihre Verwendung wirkt sich in der Regel nachteilig auf Ihre Leistung aus.

Eval ist also nicht böse. Wir könnten sagen, dass Eval böse ist, weil es ein eingängiger Weg ist, es zu sagen. Jeder Anfänger sollte sich strikt von eval fernhalten, da eval mit ziemlicher Sicherheit die falsche Lösung ist. Für bestimmte fortgeschrittene Anwendungsfälle ist eval sinnvoll, und Sie sollten es verwenden, aber natürlich auf die Fallstricke achten.


13
Ihr zweiter Fall ist sehr wichtig. In Sprachen, die eval haben, aber auch kompiliert werden, ist die Auswertung eines Strings zur Erzeugung einer Variablenreferenz nicht trivial. ZB wenn var x = 3; print(x)wird kompiliert dann hat es keine Laufzeit Wissen sein müssen , dass die Quelle den Namen „x“ verwendet. Damit var x = 3; print(eval("x"))es funktioniert, muss dieses Mapping aufgezeichnet werden. Dies ist ein echtes Problem: In Common Lisp (let ((x 3)) (print (eval 'x)))wird eine ungebundene Variablenausnahme ausgelöst, da die lexikalische Variable x keine Verbindung mit dem Namen hat, nachdem der Code kompiliert wurde.
Joshua Taylor

@JohnuaTaylor Du meinst den dritten Grund, nicht den zweiten?
user253751

1
@immibis, ich denke, er bezieht sich auf den Code im zweiten Grund. Aber Sie haben Recht, es hängt wirklich mit dem dritten Grund zusammen: der Leistung.
Winston Ewert

Sah diese Frage nicht wahr? ;)
jpmc26

@ jpmc26, nein. Aber ich habe viel davon gesehen.
Winston Ewert

20

Es läuft darauf hinaus, dass "willkürliche Codeausführung" ein Fachgespräch für "alles können" ist. Wenn jemand in der Lage ist, die Ausführung von willkürlichem Code in Ihrem Code auszunutzen, ist dies im wahrsten Sinne des Wortes die schlimmste Sicherheitslücke, die möglich ist, da er in der Lage ist, alles zu tun, was Ihr System tun kann.

"Andere möglicherweise schädliche Bugs" können durchaus Grenzen haben, was bedeutet, dass sie per Definition weniger Schaden anrichten können als eine willkürliche Codeausführung, die ausgenutzt wird.


2
Aus Gründen der Argumentation führt der Missbrauch von Zeigern auch zur Ausführung von willkürlichem Code , aber Zeiger werden viel weniger missbilligt als sie evalsind.
Dmitry Grigoryev

12
@DmitryGrigoryev Sind sie wirklich? Außerhalb von C ++ werden Zeiger im Allgemeinen als extrem gefährlich angesehen und vermieden. C # unterstützt beispielsweise Zeiger, aber dies ist in der Regel das Letzte, was Sie versuchen, nachdem Sie alle anderen Optionen ausgeschöpft haben (normalerweise aus Gründen der Leistung bei der Datenmanipulation). Die meisten modernen Sprachen unterstützen keine Zeiger. Sogar C ++ selbst bewegt sich in Richtung "sichererer" Zeiger, die versuchen, die Probleme mit beliebigen Zeigern zu lindern (z. B. Verwendung von echten Listen / Arrays anstelle von nur Zeigern, Verwendung von safe_ptr, Referenzübergabe ...).
Luaan

2
@DmitryGrigoryev: Können Sie jemandem einen Hinweis geben, dass Zeiger weniger gefährlich als eval sind?
JacquesB


1
@JacquesB, ja; es war als Witz gedacht (ich hatte erwartet, dass das Lächeln es deutlich genug machen würde). Das OP hat diese Aussage gemacht, nicht ich, also sollten Sie ihn um einen Beweis bitten.
Dmitry Grigoryev

15

Es gibt einen praktischen und einen theoretischen Grund.

Der praktische Grund ist, dass wir beobachten, dass es häufig Probleme verursacht. Es kommt selten vor, dass die Auswertung zu einer guten Lösung führt, und es kommt häufig zu einer schlechten Lösung, bei der Sie am Ende eine bessere erhalten hätten, wenn Sie vorgetragen hätten, dass die Auswertung nicht existiert und das Problem anders angegangen wären. Der vereinfachte Rat ist es also, ihn zu ignorieren. Wenn Sie einen Fall finden, in dem Sie den vereinfachten Rat ignorieren möchten, hoffen wir, dass Sie ihn ausreichend durchdacht haben, um zu verstehen, warum der vereinfachte Rat nicht anwendbar ist und der allgemeine Fallstricke werden Sie nicht betreffen.

Der theoretischere Grund ist, dass es noch schwieriger ist, Code zu schreiben , der guten Code schreibt , wenn es schwierig ist, guten Code zu schreiben . Unabhängig davon, ob Sie eval verwenden oder SQL-Anweisungen generieren, indem Sie Zeichenfolgen zusammenfügen oder einen JIT-Compiler schreiben, ist das, was Sie versuchen, oft schwieriger als erwartet. Das Potenzial für die Einschleusung von Schadcode ist ein großer Teil des Problems, aber abgesehen davon ist es im Allgemeinen schwieriger, die Richtigkeit Ihres Codes zu ermitteln, wenn Ihr Code erst zur Laufzeit vorhanden ist. Der vereinfachte Rat ist es also, die Dinge für sich zu vereinfachen: "Verwenden Sie parametrisierte SQL-Abfragen", "Verwenden Sie keine eval".

Ein Beispiel für Zaubereffekte: Es ist eine Sache, einen Lua-Compiler (oder was auch immer) oder -Interpreter in Ihr Spiel zu integrieren, damit Spieleentwickler die Zaubereffekte in einer einfacheren Sprache als C ++ (oder was auch immer) beschreiben können. Die meisten "Probleme der Auswertung" treffen nicht zu, wenn Sie nur Code auswerten, der geschrieben und getestet wurde und in das Spiel oder in DLC oder What-Have-You aufgenommen wurde. Das ist nur das Mischen von Sprachen. Die großen Probleme treffen Sie, wenn Sie versuchen, Lua (oder C ++ oder SQL oder Shell-Befehle oder was auch immer) im laufenden Betrieb zu generieren und es durcheinander zu bringen.


1
Natürlich kann die Generierung von Laufzeitcode korrekt durchgeführt werden und eval kann nützlich sein. ZB verwende ich eval häufig für Metaprogrammierungen / Makros, insbesondere wenn ich mehr Leistung möchte, als eine "sauberere" OOP oder funktionale Lösung bieten könnte. Der resultierende Code ist oft besser und einfacher, weil er weniger Boilerplate hat. Das Kennenlernen verschiedener Probleme in Bezug auf Sandboxing, Escape-Mechanismen, Code-Injection, Scoping-Regeln, Fehlerberichterstattung, Optimierung usw. setzt jedoch nicht unerhebliche Sprachkenntnisse voraus. Ohne diese Kenntnisse ist die Evaluierung äußerst gefährlich.
amon

11

Nein, es gibt keine offensichtliche historische Tatsache.

Die Übel der Eval sind von Anfang an klar zu sehen. Andere Funktionen sind leicht gefährlich. Menschen können Daten löschen. Die Leute können Daten sehen, die sie nicht sehen sollten. Menschen können Daten schreiben, die sie nicht sollten. Und sie können die meisten dieser Dinge nur tun, wenn Sie es irgendwie vermasseln und Benutzereingaben nicht validieren.

Mit eval können sie das Pentagon hacken und es so aussehen lassen, als hätten Sie es getan. Sie können Ihre Tastatureingaben überprüfen, um Ihre Passwörter zu erhalten. Vorausgesetzt, eine vollständige Sprache von Turing kann buchstäblich alles tun, wozu Ihr Computer in der Lage ist.

Und Sie können die Eingabe nicht validieren. Es ist ein beliebiger Freiform-String. Die einzige Möglichkeit zur Validierung besteht darin, einen Parser und eine Codeanalyse-Engine für die betreffende Sprache zu erstellen. Viel Glück damit.


1
... oder die Eingabe stammt von einer vertrauenswürdigen Quelle, z. B. den Zauberdefinitionsdateien für ein Spiel.
user253751

3
@immibis aber wenn der eingang vordefiniert und sicher getestet ist, warum eval verwenden, wenn er in die quelle des systems aufgenommen werden könnte?
Jules

3
@immibis - weil niemand jemals Spieldateien hackt ...
Telastyn

2
... das ist nicht das, was "Turing komplett" bedeutet (Turing-Vollständigkeit ist einen Schritt von irrelevantem zu realem Computing entfernt).
Leushenko

1
@Telastyn: Was ein Javascript-Programm nicht kann. Oder sogar ein C ++ - Programm. Javascript läuft in einer Sandbox (Browser), die sich in einer anderen Sandbox befindet (Ring 3 in x86). Der Interrupt-Vektor befindet sich außerhalb dieser Sandbox und wird vom Betriebssystem gesteuert. Und diese äußere Sandbox, Ring 3, ist CPU-verstärkt.
MSalters

6

Ich denke, es läuft auf die folgenden Aspekte hinaus:

  • Notwendigkeit
  • (Bewachter) Gebrauch
  • Zugriff
  • Überprüfbarkeit
  • Mehrstufige Angriffe

Notwendigkeit

Hallo zusammen, ich habe dieses extrem coole Bildbearbeitungsprogramm geschrieben (erhältlich für $ 0.02). Nachdem Sie das Bild geöffnet haben, können Sie eine Vielzahl von Filtern auf Ihr Bild anwenden. Sie können einige sogar selbst mit Python (dem Programm, in dem ich die Anwendung geschrieben habe) schreiben. Ich werde nur evalauf Ihre Eingabe verwenden, in dem Vertrauen, dass Sie ein seriöser Benutzer sind.

(später)

Vielen Dank für den Kauf. Wie Sie sehen, funktioniert es genau so, wie ich es versprochen habe. Oh, du willst ein Bild öffnen? Nein, kannst du nicht. Ich werde die readMethode nicht verwenden , da sie etwas unsicher ist. Sparen? Nein, ich werde nicht verwenden write.

Ich versuche zu sagen: Sie benötigen Lese- / Schreibzugriff für fast alle grundlegenden Tools. Gleiches gilt für die Speicherung der Highscores Ihres ach so tollen Spiels.

Ohne Lesen / Schreiben ist Ihr Bildeditor unbrauchbar. Ohne eval? Ich schreibe dir ein benutzerdefiniertes Plugin dafür!

(Bewachter) Gebrauch

Viele Methoden können möglicherweise gefährlich sein. Wie zum Beispiel das readund write. Ein häufiges Beispiel ist ein Webdienst, mit dem Sie Bilder aus einem bestimmten Verzeichnis lesen können, indem Sie den Namen angeben. Der Name kann jedoch ein beliebiger gültiger (relativer) Pfad auf dem System sein, sodass Sie alle Dateien lesen können, auf die der Webdienst Zugriff hat, nicht nur die Bilder. Der Missbrauch dieses einfachen Beispiels wird als "Pfadüberquerung" bezeichnet. Wenn Ihre App die Pfadüberquerung zulässt, ist dies schlecht. Ein, readohne sich dagegen zu verteidigen, kann durchaus als böse bezeichnet werden.

In anderen Fällen steht der String für readjedoch vollständig unter der Kontrolle des Programmierers (möglicherweise fest codiert?). In diesem Fall ist es kaum böse zu gebrauchen read.

Zugriff

Nun ein weiteres einfaches Beispiel mit eval.

Irgendwo in Ihrer Web-App möchten Sie dynamische Inhalte. Sie gestatten den Administratoren die Eingabe von ausführbarem Code. Da die Administratoren vertrauenswürdige Benutzer sind, kann dies theoretisch in Ordnung sein. Stellen Sie einfach sicher, dass Sie keinen Code ausführen, der von Nicht-Administratoren gesendet wurde.

(Das heißt, bis Sie diesen netten Administrator gefeuert haben, aber vergessen haben, seinen Zugriff zu widerrufen. Jetzt wird Ihre Web-App verworfen).

Überprüfbarkeit.

Ein weiterer wichtiger Aspekt ist meiner Meinung nach, wie einfach es ist, Benutzereingaben zu überprüfen.

Benutzereingaben in einem Leseaufruf verwenden? Stellen Sie einfach (sehr) sicher, dass die Eingabe für den Leseaufruf nichts Bösartiges enthält. Normalisieren Sie den Pfad und vergewissern Sie sich, dass sich die geöffnete Datei in Ihrem Medienverzeichnis befindet. Das ist jetzt sicher.

Benutzereingaben bei einem Schreibanruf? Gleich!

SQL-Injektion? Entkomme einfach oder verwende parametrisierte Abfragen und du bist sicher.

Eval? Wie verifizierst du die Eingabe, die für den evalAnruf verwendet wird? Sie können sehr hart arbeiten, aber es ist wirklich sehr schwer (wenn nicht unmöglich), dafür zu sorgen, dass es sicher funktioniert.

Mehrstufige Angriffe

Jetzt müssen Sie jedes Mal, wenn Sie Benutzereingaben verwenden, die Vorteile der Verwendung gegen die Gefahren abwägen. Schützen Sie die Nutzung so weit wie möglich.

Betrachte noch einmal das evalfähige Zeug im Admin-Beispiel. Ich habe dir doch gesagt, dass das in Ordnung ist.

Bedenken Sie nun, dass es in Ihrer Web-App tatsächlich eine Stelle gibt, an der Sie vergessen haben, Benutzerinhalte (HTML, XSS) zu umgehen. Das ist eine geringere Straftat als eine vom Benutzer zugängliche Bewertung. Unter Verwendung des nicht entkoppelten Benutzerinhalts kann ein Benutzer jedoch den Webbrowser eines Administrators übernehmen und über die Administratorsitzung einen möglichen evalBlob hinzufügen , wodurch wiederum der vollständige Systemzugriff ermöglicht wird.

(Dieselbe mehrstufige Attacke kann mit SQL-Injection anstelle von XSS durchgeführt werden, oder es werden beliebige Datei-Schreibvorgänge ausgeführt, die den ausführbaren Code ersetzen, anstatt zu verwenden. eval)


2
"Sie können sehr hart arbeiten, aber es ist wirklich sehr schwer (wenn nicht unmöglich), dafür zu sorgen, dass es sicher funktioniert." - Es ist unmöglich. Einfacher Beweis: Anstatt herauszufinden, ob der vom Benutzer bereitgestellte Code "sicher" ist oder nicht, versuchen Sie einfach, etwas viel, viel Einfacheres herauszufinden und zu sehen, wie schwer das bereits ist: Hält der vom Benutzer bereitgestellte Code an?
Jörg W Mittag

2
@ JörgWMittag: gib mir ein programm geschrieben in coq und ich werde es beweisen.
André Paramés

1
@ JörgWMittag: Einverstanden. Abhängig von der Sprache und dem Umfang der Benutzereingabe. Es könnte genauso gut sein eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder"). Es ist möglich zu überprüfen, ob die Eingabe alphanumerisch ist. Außerdem ist 'does it halt' orthogonal zu 'does it change / access state, den es nicht berühren sollte' und 'does it cal methods, die es nicht aufrufen sollte'.
Sjoerd Job Postmus

3
@ JörgWMittag Es ist unmöglich zu beweisen, dass ein bestimmtes Programm etwas nicht kann, aber es ist nicht unmöglich, eine eingeschränkte Menge von Programmen, für die Sie es beweisen können, konservativ zu definieren und zu erzwingen, dass Eingabeprogramme Mitglieder dieser Menge sind.
user253751

3

Damit diese Funktion überhaupt funktioniert, muss eine Reflektionsebene vorhanden sein, die den vollständigen Zugriff auf den internen Status des gesamten Programms ermöglicht.

Für interpretierte Sprachen kann ich einfach den Interpreter-Status verwenden, der einfach ist, aber in Kombination mit JIT-Compilern die Komplexität noch erheblich erhöht.

Ohne evalkann der JIT-Compiler häufig nachweisen, dass auf die lokalen Daten eines Threads nicht von einem anderen Code aus zugegriffen wird. Daher ist es durchaus akzeptabel, Zugriffe neu zu ordnen, Sperren auszulassen und häufig verwendete Daten für längere Zeit zwischenzuspeichern. Wenn ein anderer Thread eine evalAnweisung ausführt , muss möglicherweise der laufende JIT-kompilierte Code damit synchronisiert werden. Daher benötigt der JIT-generierte Code plötzlich einen Fallback-Mechanismus, der innerhalb eines vernünftigen Zeitraums zur nicht optimierten Ausführung zurückkehrt.

Diese Art von Code weist in der Regel viele subtile, schwer zu reproduzierende Fehler auf und schränkt gleichzeitig die Optimierung im JIT-Compiler ein.

Für kompilierte Sprachen ist der Kompromiss sogar noch schlimmer: Die meisten Optimierungen sind verboten, und ich muss umfangreiche Symbolinformationen und einen Interpreter bereithalten, sodass sich die zusätzliche Flexibilität im Allgemeinen nicht lohnt - es ist oft einfacher, eine Schnittstelle zu einigen internen zu definieren Strukturen, zB durch eine Skript geben Ansicht und Controller gleichzeitigen Zugriff auf das Programm des Modells .


"Damit diese Funktion überhaupt funktioniert, muss ich eine Reflektionsebene haben, die den vollständigen Zugriff auf den internen Status des gesamten Programms ermöglicht." Nein, nur auf die Teile, die Sie beeinflussen möchten. Im Fall von OpenERP / Odoo hat der zu evaluierende Code nur Zugriff auf eine sehr begrenzte Anzahl von Variablen und Funktionen, die er aufrufen kann, und alle sind thread-lokal.
André Paramés

1

Ich lehne die Prämisse ab, evaldie als böser als Zeigerarithmetik oder gefährlicher als direkter Speicher- und Dateisystemzugriff angesehen wird. Ich kenne keinen vernünftigen Entwickler, der das glauben würde. Darüber hinaus werden Sprachen, die Zeigerarithmetik / direkten Speicherzugriff unterstützen, normalerweise nicht unterstützt evalund umgekehrt. Ich bin mir also sicher, wie oft ein solcher Vergleich überhaupt relevant wäre.

Dies evalkönnte jedoch eine bekanntere Sicherheitsanfälligkeit sein, da sie von JavaScript unterstützt wird. JavaScript ist eine Sandbox-Sprache ohne direkten Speicher- oder Dateisystemzugriff, sodass diese Sicherheitsanfälligkeiten nur Schwachstellen in der Sprachimplementierung selbst ausschließen. Evalist daher eines der gefährlichsten Merkmale der Sprache, da es die Möglichkeit der Ausführung von willkürlichem Code eröffnet. Ich glaube, dass viel mehr Entwickler in JavaScript als in C / C ++ evalentwickeln. Daher ist es für die Mehrheit der Entwickler einfach wichtiger, sich dessen bewusst zu sein, als dass Pufferüberläufe auftreten.


0

Kein seriöser Programmierer würde Eval als "böse" bezeichnen. Es ist einfach ein Programmierwerkzeug wie jedes andere. Die Angst vor dieser Funktion hat nichts mit der Populärkultur zu tun. Es ist einfach ein gefährlicher Befehl, der häufig missbraucht wird und schwerwiegende Sicherheitslücken einführt und die Leistung beeinträchtigt. Aus eigener Erfahrung würde ich sagen, dass es selten ein Programmierproblem gibt, das auf andere Weise nicht sicherer und effizienter gelöst werden kann. Die Programmierer, die am wahrscheinlichsten eval verwenden, sind diejenigen, die wahrscheinlich am wenigsten dafür qualifiziert sind, dies sicher zu tun.

Allerdings gibt es Sprachen, in denen die Verwendung von eval angebracht ist. Perl fällt mir ein. Ich persönlich finde jedoch, dass es in anderen, moderneren Sprachen, die die strukturierte Ausnahmebehandlung von Haus aus unterstützen, nur sehr selten benötigt wird.


dies versucht nicht einmal, die gestellte Frage zu beantworten: "Gibt es eine historische Tatsache dafür, dass diese Angst Teil der Populärkultur wird?". Sehen Sie, wie man antwortet
Mücke

Die Frage basiert meiner Meinung nach auf einer falschen Prämisse, daher habe ich sie als solche beantwortet.
user1751825

0

Ich denke, dass Sie im folgenden Teil Ihrer Frage (Hervorhebung meiner) recht gut darauf eingehen:

Sie haben eine gute Verwendung, solange sie richtig verwendet werden

Für die 95%, die es richtig benutzen, ist alles gut und schön; aber es wird immer Leute geben, die es nicht richtig benutzen. Einige davon werden auf Unerfahrenheit und mangelnde Fähigkeiten zurückzuführen sein, der Rest wird böswillig sein.

Es wird immer Leute geben, die Grenzen überschreiten und Sicherheitslücken finden wollen - manche für gut, manche für schlecht.

Was das historische Faktum betrifft, so evalermöglichen Typfunktionen im Wesentlichen die Ausführung von beliebigem Code, der zuvor in populären Web-CMS, Joomla! . Mit Joomla! Wenn mehr als 2,5 Millionen Websites weltweit mit Strom versorgt werden , kann dies nicht nur den Besuchern dieser Websites, sondern auch der Infrastruktur, auf der sie gehostet werden, und der Reputation der Websites / Unternehmen, die ausgenutzt wurden, großen Schaden zufügen.

Der Joomla! Ein Beispiel mag einfach sein, aber es wurde aufgezeichnet.


0

Es gibt einige gute Gründe, von der Verwendung abzuraten eval(obwohl einige für bestimmte Sprachen spezifisch sind).

  • Die von verwendete Umgebung (lexikalisch und dynamisch) evalist häufig überraschend (das heißt, Sie denken, sie eval(something here)sollte eine Sache tun, aber sie tut eine andere, was möglicherweise Ausnahmen auslöst).
  • Es gibt häufig einen besseren Weg, um das Gleiche zu erreichen (die Verkettung konstruierter lexikalischer Abschlüsse ist manchmal eine bessere Lösung, aber das kann durchaus Common-Lisp-spezifisch sein).
  • Es ist viel zu einfach, unsichere Daten auszuwerten (obwohl dies meistens verhindert werden kann).

Ich persönlich würde nicht so weit gehen zu sagen, dass es böse ist, aber ich werde immer die Verwendung von evalCode in Frage stellen , mit Formulierungen wie "Haben Sie hier einen Code in Betracht gezogen ?" (wenn ich Zeit habe, mindestens einen vorläufigen Ersatz zu machen), oder "sind Sie sicher, dass eine Bewertung hier wirklich die beste Lösung ist?" (wenn ich nicht).


dies versucht nicht einmal, die gestellte Frage zu beantworten: "Gibt es eine historische Tatsache dafür, dass diese Angst Teil der Populärkultur wird?". Sehen Sie, wie man antwortet
Mücke

0

In Minskys Society of Mind , Kapitel 6.4, sagt er

Es gibt eine Möglichkeit, wie ein Geist sich selbst beobachten und trotzdem verfolgen kann, was passiert. Teilen Sie das Gehirn in zwei Teile, A und B. Verbinden Sie die Ein- und Ausgänge des A-Gehirns mit der realen Welt - so kann es spüren, was dort passiert. Aber verbinde das B-Gehirn überhaupt nicht mit der Außenwelt; Schließen Sie es stattdessen so an, dass das A-Gehirn die Welt des B-Gehirns ist!

Wenn ein Programm (B) ein anderes Programm (A) schreibt, funktioniert es als Metaprogramm. Gegenstand von B ist Programm A.

Es gibt ein C-Programm. Das ist derjenige in deinem Kopf, der Programm B schreibt.

Die Gefahr ist, dass es jemanden (C ') mit böser Absicht geben kann, der in diesen Prozess eingreifen kann, so dass Sie Dinge wie SQL-Injection erhalten.

Die Herausforderung besteht darin, Software intelligenter zu machen, ohne sie auch gefährlicher zu machen.


Zwei positive und zwei negative Stimmen. Sieht so aus, als würde das einen Nerv treffen.
Mike Dunlavey

0

Sie haben hier viele gute Antworten und der Hauptgrund ist eindeutig, dass die Ausführung von willkürlichem Code schlecht ist. Ich möchte jedoch einen weiteren Faktor hinzufügen, den andere nur am Rande von:

Es ist wirklich schwierig, Probleme mit Code zu beheben, der aus einer Textzeichenfolge ausgewertet wird. Ihre normalen Debugging-Tools sind so gut wie direkt aus dem Fenster und Sie sind auf die Nachverfolgung oder das Echo der alten Schule reduziert. Offensichtlich ist das nicht so wichtig, wenn Sie ein Fragment in einem Einzeiler haben, das Sie möchten, evalaber als erfahrener Programmierer können Sie wahrscheinlich eine bessere Lösung dafür finden, wohingegen die Codegenerierung in größerem Maßstab irgendwo anders sein kann als eine Evaluierungsfunktion wird zu einem potenziell nützlichen Verbündeten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.