2015-09-10 10 views
5

Ich möchte eine Zeichenfolge aus einer Eingabedatei einlesen (die vom Benutzer möglicherweise geändert wurde oder nicht). Ich möchte diese Zeichenfolge als eine Format-Anweisung behandeln, die mit einer festen Anzahl von Argumenten aufgerufen wird. Allerdings verstehe ich, dass einige Format-Direktiven (insbesondere die ~/ in den Sinn kommt) potenziell zum Einfügen von Funktionsaufrufen verwendet werden könnte, was diesen Ansatz von Natur aus unsicher macht.Sicheres Parsen von Format-Direktiven in Common Lisp

Wenn read unter Verwendung von Daten in Common Lisp parsen, stellt die Sprache die *read-eval* dynamischen Variable, die eingestellt werden kann nil#. Code-Injektion zu deaktivieren. Ich suche nach etwas ähnlichem, das Code-Injection und arbiträre Funktionsaufrufe innerhalb von Format-Direktiven verhindern würde.

Antwort

4

Wenn der Benutzer keinen benutzerdefinierten Code, sondern nur Formatstrings einfügen kann, können Sie die Probleme von print-object vermeiden. Denken Sie daran, with-standard-io-syntax (oder eine angepasste Version davon) zu verwenden, um die genaue Art der Ausgabe zu steuern, die Sie generieren werden (denken Sie an *print-base*, ...).

Sie können die Eingabestrings scannen, um das Vorhandensein von ~/ zu erkennen (aber ~~/ ist gültig) und das Format, das Konstrukte mit der schwarzen Liste enthält, nicht interpretieren. Allerdings sind einige Analysen schwieriger und Sie müssen möglicherweise zur Laufzeit handeln.

Zum Beispiel, wenn die Formatzeichenfolge fehlerhaft ist, werden Sie wahrscheinlich einen Fehler auftreten, der behandelt werden muss (auch können Sie den erwarteten Argumenten schlechte Werte geben).

Selbst wenn der Benutzer nicht bösartig ist, können Sie auch Probleme mit Iteration Konstrukte haben:

~{<X>~:*~} 

... hört nie auf, weil ~:* aktuelle Argument zurückgespult. Um dies zu umgehen, müssen Sie berücksichtigen, dass <X> möglicherweise etwas drucken kann. Sie könnten diese beiden Strategien implementieren:

  • haben ein Timeout-Zeit-Formatierung
  • haben die zugrunde liegende Stream Reichweite End-of-Datei nimmt zu begrenzen, wenn zu viel zu schreiben (z schreibt in einen String-Puffer).

Es kann andere Probleme geben, die ich derzeit nicht sehe, sei vorsichtig.

+1

Danke. Ich hatte nicht einmal über Endlosschleife Probleme gedacht. Bei Problemen wie diesen werde ich wahrscheinlich meine eigene Mikrosprache für Formatbezeichner schreiben, anstatt zu versuchen, 'Format' zu optimieren. –

+0

@SilvioMayolo Dies ist auch eine gute Vorgehensweise. Aber nehmen Sie sich etwas Zeit, um zu sehen, ob es andere Formate gibt: Ich denke an "cl-interpol", aber es könnte andere geben. Viel Glück! – coredump

+1

Sehr schöner Punkt über Iterationskonstrukte! –

3

Es ist nicht nur ~/, über die Sie sich Gedanken machen müssten. Die hübsche Druckerfunktionalität hat viele Möglichkeiten zur Codeerweiterung, und sogar ~ A kann Probleme verursachen, weil Objekte Druckobjekt definiert sind. Z. B.

(defclass x()()) 

(defmethod print-object ((x x) stream) 
    (format *error-output* "Executing arbitrary code...~%") 
    (call-next-method x stream)) 

CL-USER> (format t "~A" (make-instance 'x)) 
Executing arbitrary code... 
#<X {1004E4B513}> 
NIL 

ich glaube, Sie für sich selbst zu definieren, bräuchten die Richtlinien sind sicher, mit was auch immer Kriterien, die Sie für wichtig halten, und dann nur diejenigen.