Eine Funktion f()
verwendet eval()
(oder etwas so Gefährliches) Daten, die ich local_file
auf dem Computer erstellt und gespeichert habe, auf dem mein Programm ausgeführt wird:
import local_file
def f(str_to_eval):
# code....
# ....
eval(str_to_eval)
# ....
# ....
return None
a = f(local_file.some_str)
f()
ist sicher zu laufen, da die Zeichenfolgen, die ich ihm zur Verfügung stelle, meine eigenen sind.
Wenn ich mich jedoch jemals dazu entscheide, es für etwas Unsicheres (z. B. Benutzereingaben) zu verwenden, können furchtbare Fehler auftreten . Wenn das nicht local_file
mehr lokal ist, entsteht eine Sicherheitsanfälligkeit, da ich dem Computer vertrauen muss, der auch diese Datei bereitstellt.
Wie soll ich sicherstellen, dass ich nie "vergesse", dass die Verwendung dieser Funktion unsicher ist (es sei denn, bestimmte Kriterien sind erfüllt)?
Hinweis: eval()
ist gefährlich und kann normalerweise durch etwas Sicheres ersetzt werden.
quelle
Antworten:
Definieren Sie einen Typ, um „sichere“ Eingaben zu dekorieren. Stellen Sie in Ihrer Funktion
f()
sicher, dass das Argument diesen Typ hat, oder geben Sie einen Fehler aus. Seien Sie schlau genug, um niemals eine Verknüpfung zu definierendef g(x): return f(SafeInput(x))
.Beispiel:
Dies kann zwar leicht umgangen werden, erschwert dies jedoch aus Versehen. Die Leute könnten eine solche drakonische Typprüfung kritisieren, aber sie würden den Punkt verfehlen. Da der
SafeInput
Typ nur ein Datentyp und keine objektorientierte Klasse ist, die in Unterklassen unterteilt werden könnte, ist die Überprüfung der Typidentität mittype(x) is SafeInput
sicherer als die Überprüfung der Typkompatibilität mitisinstance(x, SafeInput)
. Da wir einen bestimmten Typ erzwingen möchten, ist es auch hier nicht zufriedenstellend, den expliziten Typ zu ignorieren und nur implizite Ententypisierung durchzuführen. Python hat ein Typsystem, also verwenden wir es, um mögliche Fehler zu erkennen!quelle
assert
wird automatisch entfernt, da ich optimierten Python-Code verwende. So etwasif ... : raise NotSafeInputError
wäre nötig.eval()
Methode in eine Methode zu verschiebenSafeInput
, damit Sie keine explizite Typprüfung benötigen. Geben Sie der Methode einen Namen, der in keiner Ihrer anderen Klassen verwendet wird. Auf diese Weise können Sie das Ganze immer noch zu Testzwecken verspotten.eval
der Zugriff auf lokale Variablen möglich ist, hängt der Code möglicherweise davon ab, wie er die Variablen mutiert. Wenn Sie die Auswertung in eine andere Methode verschieben, können lokale Variablen nicht mehr mutiert werden.SafeInput
Konstruktor einen Namen / ein Handle der lokalen Datei übernimmt und den Lesevorgang selbst durchführt, um sicherzustellen, dass die Daten tatsächlich aus einer lokalen Datei stammen.Wie Joel einmal betont hat, lassen Sie falschen Code falsch aussehen (scrollen Sie nach unten zum Abschnitt "The Real Solution" oder lesen Sie ihn besser noch vollständig; es lohnt sich, auch wenn er Variablen anstelle von Funktionsnamen anspricht). Daher schlage ich demütig vor, Ihre Funktion in so etwas wie umzubenennen
f_unsafe_for_external_use()
- Sie werden höchstwahrscheinlich selbst ein Abkürzungsschema entwickeln.Edit: Ich denke, Amons Vorschlag ist eine sehr gute, OO-basierte Variation des gleichen Themas :-)
quelle
Ergänzend zum Vorschlag von @amon können Sie hier auch das Strategiemuster sowie das Methodenobjektmuster kombinieren.
Und dann eine "normale" Implementierung
Und eine Admin-Input-Eval-Implementierung
(Hinweis: Mit einem realen Beispiel kann ich möglicherweise ein besseres Beispiel geben.)
quelle