Frage

Ich habe mit eval Funktion von Rubin viele Male. Aber ich habe gehört, wie Leute sagen evals sind böse. Auf die Frage, warum und wie, ich könnte nie einen überzeugenden Grund, nicht zu verwenden, es bekommen. Sind sie wirklich böse? Wenn ja, in welcher Weise? Was sind möglich „sicherer“ Optionen eval?

War es hilfreich?

Lösung

Wenn Sie einen String abgegeben evaling durch, oder durch den Benutzer modifizierbar, dies ermöglicht die Ausführung beliebige Codes gleichkommt. Stellen Sie sich vor, wenn die Zeichenfolge ein OS Aufruf enthalten rm -rf / oder ähnliches. Das heißt, in Situationen, in denen Sie die Saiten wissen sind in geeigneter Weise eingeschränkt oder Ihr Ruby-Interpreter in geeigneter Weise Sandbox oder im Idealfall beide können eval außerordentlich leistungsfähig sein.

Das Problem ist analog href="http://en.wikipedia.org/wiki/SQL_injection" rel="noreferrer"> SQL-Injection- eval von einer ganz bestimmten Form zu sein, und nicht alle der Anweisung muss vom Anwender vorgelegt wird, nur wenige Variablen, ein mathematischer Ausdruck, oder ähnliches, können Sie in diesen kleinen Stücken vom Benutzer nehmen, sie zu desinfizieren, wenn nötig, dann die sichere Template-Anweisung mit der Benutzereingabe bewerten an den entsprechenden Stellen eingesteckt.

Andere Tipps

In Ruby gibt es mehrere Kniffe, die besser geeignet sein könnten als eval():

  1. Es ist #send, die Sie eine Methode, deren Namen Sie haben als Zeichenfolge aufrufen können und übergeben Parameter zu.
  2. yield können Sie einen Code-Block zu einer Methode zu übergeben, die im Rahmen des Aufnahmeverfahrens ausgeführt werden.
  3. Oft ist die einfache Kernel.const_get("String") ausreicht, um die Klasse zu erhalten, deren Namen Sie als String haben.

Ich glaube, ich bin nicht in der Lage, sie richtig im Detail zu erklären, so dass ich Ihnen nur gab die Hinweise, wenn Sie daran interessiert sind, werden Sie Google.

eval ist nicht nur unsicher (wie an anderer Stelle darauf hingewiesen wurde), es ist auch langsam. Jedes Mal, sie ausgeführt wird, muss der AST des evaled Code analysiert werden (und zB für JRuby, wandte sich an Bytecode) neu, die eine String-schwerer Operation und ist wahrscheinlich auch schlecht für die Cache-Ort (unter der Annahme, dass ein Lauf Programm nicht viel eval, und die entsprechenden Teile des Dolmetschers sind somit Cache-kalt, abgesehen davon, dass groß).

Warum gibt es eval überhaupt in Ruby, fragen Sie? „Denn wir können“ meist - In der Tat, wenn eval (für die Programmiersprache LISP) erfunden wurde, war es meist für die Show ! Mehr zu dem Punkt, eval verwendet, ist das Richtige, wenn Sie wollen, für metaprogramming Aufgaben „einen Dolmetscher in Ihren Dolmetscher hinzufügen“ wie ein Prä-Prozessor, einen Debugger oder eine Template-Engine zu schreiben. Die gemeinsame Idee für solche Anwendungen ist eine Ruby-Code und Call eval darauf, und es schlägt sicher neu zu erfinden und die Implementierung eine domänenspezifisches Spielzeug Sprache zu massieren, ein pitfall auch als Greenspun Zehnte Regel . Die Einsprüche werden: Vorsicht vor den Kosten für eine Template-Engine zum Beispiel alle deine evaling beim Start keine Zeit laufen; und do eval nicht vertrauenswürdigen Code, es sei denn Sie wissen, wie zu „zähmen“ es, also wählen und eine sichere Teilmenge der Sprache erzwingt nach der Theorie von , wie das war für Java getan , ich bin nicht bekannt, dass solche Bemühungen für Ruby leider)

.

Es macht schwierig debuggen. Es macht Optimierung schwierig. Vor allem aber ist es in der Regel ein Zeichen dafür, dass es ein besserer Weg, um zu tun, was Sie zu tun versuchen.

Wenn Sie uns sagen, was Sie versuchen, mit eval zu erreichen, können Sie einige weitere relevante Antworten erhalten in Bezug auf Ihr spezielles Szenario.

Eval ist eine unglaublich leistungsstarke Funktion, die sorgfältig verwendet werden soll. Neben den Sicherheitsfragen von Matt J wies darauf hin, finden Sie auch, dass das Debuggen Laufzeit ausgewertet Code extrem schwierig ist. Ein Problem bei einer Laufzeit ausgewertet Codeblock wird schwierig sein, für die Dolmetscher Ausdruck zu bringen -. So sucht es wird schwierig sein,

aber sagt, dass, wenn Sie mit diesem Thema vertraut sind, und sind nicht besorgt über die Sicherheitslücke, dann sollten Sie nicht vermeiden, eine der Funktionen verwenden, den Rubin macht so attraktiv wie es ist.

In bestimmten Situationen ein gut platzierter eval ist klug und reduziert die Menge an Code erforderlich. Zusätzlich zu den Sicherheitsbedenken, die von Matt J genannt wurden, müssen Sie auch, sich fragen eine ganz einfache Frage:

Wenn alles gesagt und getan ist, kann jemand den Code lesen und verstehen, was Sie getan haben?

Wenn die Antwort nein ist, dann, was Sie schon mit einem eval gewonnen wird Wartbarkeit verlassen. Dieses Problem ist nicht nur anwendbar, wenn Sie in einem Team arbeiten, aber es ist auch für Sie -. Sie Ihren Code Monaten in der Lage sein wollen, zurück zu blicken, wenn nicht Jahre von jetzt an, und wissen, was Sie getan haben

Wenn Sie alles unterwegs sind, die man von der „Außenseite“ erhalten eval, Ihr tut etwas falsch, und es ist sehr unangenehm. Es ist sehr schwer, den Code genug, um zu entkommen für sie sicher zu sein, so würde ich es ziemlich unsicher betrachten. Wenn Sie jedoch eval verwenden für die Vervielfältigung oder andere ähnliche Dinge zu vermeiden, wie das folgende Codebeispiel, es ist in Ordnung, es zu benutzen.

class Foo
  def self.define_getters(*symbols)
    symbols.each do |symbol|
      eval "def #{symbol}; @#{symbol}; end"
    end
  end

  define_getters :foo, :bar, :baz
end

jedoch zumindest in Ruby 1.9.1, Ruby hat wirklich mächtig Meta-Programmierung Methoden, und man konnte die folgende stattdessen tun:

class Foo
  def self.define_getters(*symbols)
    symbols.each do |symbol|
      define_method(symbol) { instance_variable_get(symbol) }
    end
  end

  define_getters :foo, :bar, :baz
end

Für die meisten Zwecke wollen Sie diese Methoden verwenden und kein Entkommen benötigt wird.

Die andere schlechte Sache über eval ist die Tatsache, dass (zumindest in Ruby), es ist ziemlich langsam, da die Interpreter die Zeichenfolge analysieren muss, und dann den Code innerhalb der aktuellen Bindung auszuführen. Die anderen Methoden rufen die C-Funktion direkt, und deshalb sollten Sie ganz einen Geschwindigkeitsschub bekommen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top