Es gibt viele Fragen zu SO über Pythons Eval auf unsicheren Strings (zB: Sicherheit von Pythons eval () auf nicht vertrauenswürdigen Strings? , Python: mach eval sicher ). Die einhellige Antwort ist, dass dies eine schlechte Idee ist.
Ich fand jedoch wenig Informationen darüber, welche Strings als sicher betrachtet werden können (falls vorhanden). Jetzt frage ich mich, ob es eine Definition von "sicheren Strings" gibt (zB: eine Zeichenkette, die nur Ascii-Zeichen in Kleinbuchstaben enthält oder eines der Zeichen + - * / ()). Die Exploits, die ich fand, beruhten entweder auf _.,: [] '' Oder ähnlichem. Kann ein solcher Ansatz sicher sein (zur Verwendung in einer Graph-Painting-Web-Anwendung)?
Ansonsten denke ich, dass die Verwendung eines Analysepakets, wie Alex Martelli vorgeschlagen hat, der einzige Weg ist.
BEARBEITEN: Leider gibt es keine Antworten, die eine überzeugende Erklärung dafür liefern, warum / wie die obigen Strings als unsicher zu betrachten sind (ein winziger funktionierender Exploit) oder Erklärungen für das Gegenteil. Mir ist bewusst, dass die Verwendung von Eval vermieden werden sollte, aber das ist nicht die Frage. Daher werde ich dem ersten, der entweder einen funktionierenden Exploit oder eine wirklich gute Erklärung findet, ein Kopfgeld geben, weshalb eine wie oben beschrieben gemangelte Zeichenkette als (un) sicher betrachtet wird.
Hier haben Sie einen funktionierenden "Exploit" mit Ihren Restriktionen - enthält nur Ascii-Zeichen in Kleinbuchstaben oder eines der Zeichen + - * / (). Es beruht auf einer zweiten Eval-Ebene.
%Vor%Ausgabe:
%Vor%Dies ist ein sehr trivialer "Exploit". Ich bin mir sicher, dass es unzählige andere gibt, sogar mit weiteren Charakterbeschränkungen. Es muss wiederholt werden, dass man immer einen Parser oder ast.literal_eval () verwenden sollte. Nur wenn die Token analysiert werden, kann sichergestellt werden, dass die Zeichenfolge sicher ausgewertet werden kann. Alles andere wettet gegen das Haus.
Nein, es gibt keinen oder zumindest keinen vernünftigen, wirklich sicheren Weg. Python ist eine hochdynamische Sprache, und die Kehrseite davon ist, dass es sehr einfach ist, jeden Versuch, die Sprache zu sperren, zu untergraben.
Sie müssen entweder einen eigenen Parser für die gewünschte Teilmenge schreiben oder für bestimmte Fälle, die auf sie stoßen, etwas Vorheriges wie ast.literal_eval()
verwenden. Verwenden Sie ein Werkzeug, das für die jeweilige Aufgabe entwickelt wurde, anstatt zu versuchen, eine vorhandene Person dazu zu bringen, die gewünschte Aufgabe schlecht zu erfüllen.
Bearbeiten:
Ein Beispiel für zwei Strings, die, während sie zu Ihrer Beschreibung passen, wenn eval()
ed in der Reihenfolge ist, beliebigen Code ausführen würde (in diesem speziellen Beispiel wird evil.__method__()
ausgeführt.
Ein Exploit, der dem von goncalopp ähnelt, aber auch die Einschränkung erfüllt, dass der String 'eval'
kein Teilstring des Exploits ist:
Es verwendet eine Kombination aus Genexp und Tupel-Entpacken, um getattr
mit zwei Argumenten ohne das Komma aufzurufen.
Eine Beispielverwendung:
%Vor% Dies beweist, dass das Definieren von Einschränkungen nur für den Text, der den Code sicher macht, wirklich schwierig ist. Selbst Dinge wie 'eval' in code
sind nicht sicher. Entweder müssen Sie die Möglichkeit, einen Funktionsaufruf auszuführen, überhaupt entfernen, oder Sie müssen alle gefährlichen integrierten Komponenten aus der Umgebung von eval
entfernen. Mein Exploit zeigt auch, dass getattr
so schlecht ist wie eval
, auch wenn Sie das Komma nicht verwenden können, da Sie beliebig in die Objekthierarchie gehen können. Zum Beispiel können Sie die echte Funktion eval
erhalten, auch wenn die Umgebung dies nicht bietet:
Auch wenn Sie alle integrierten Komponenten entfernen, wird der Code sicher:
%Vor% Beachten Sie, dass das Setzen von '__builtins__'
auf None
auch chr
, list
, tuple
usw. entfernt.
Die Kombination der Zeichen restrinctions und '__builtins__'
bis None
ist vollkommen sicher, da der Benutzer keine Möglichkeit hat, auf irgendetwas zuzugreifen. Er kann nicht die .
, die Klammern []
oder eine eingebaute Funktion oder einen eingebauten Typ verwenden.
Obwohl ich auf diese Weise sagen muss, was Sie bewerten können, ist ziemlich begrenzt. Sie können nicht viel mehr tun als Operationen mit Zahlen.
Wahrscheinlich ist es genug, eval
, getattr
und chr
von den eingebauten zu entfernen, um den Code sicher zu machen, zumindest kann ich mir keinen Weg vorstellen, einen Exploit zu schreiben, der keinen benutzt von ihnen.
Ein "Parsing" -Ansatz ist wahrscheinlich sicherer und bietet mehr Flexibilität. Zum Beispiel dieses Rezept ist ziemlich gut und kann auch leicht angepasst werden, um weitere Einschränkungen hinzuzufügen. p>
Um zu lernen, wie man sicher eval macht, empfehle ich RestrictedPython-Modul (über 10 Jahre Produktionsnutzung, ein schönes Stück Python-Software)
RestrictedPython verwendet den Python-Quellcode und modifiziert seinen AST (Abstract Syntax Tree), um die Auswertung in der Sandbox sicher zu machen, ohne irgendwelche Python-Interna zu verlieren, die das Verlassen der Sandbox erlauben könnten.
Aus dem RestrictedPython-Quellcode erfahren Sie, welche Tricks erforderlich sind, um Python-Sandboxes sicher zu machen.
Sie sollten eval wahrscheinlich eigentlich meiden.
Aber wenn Sie dabei bleiben, können Sie einfach sicherstellen, dass Ihre Strings alphanumerisch sind. Das sollte sicher sein.
Es reicht nicht aus, Routinen zur Bereinigung von Eingaben zu erstellen. Sie müssen auch sicherstellen, dass die Bereinigung nicht versehentlich ausgelassen wird. Eine Möglichkeit, dies zu tun, ist Taint Checking .