2015-09-10 2 views
5

Я хотел бы прочитать строку из входного файла (который может или не был изменен пользователем). Я хотел бы рассматривать эту строку как директиву формата, которую нужно вызывать с фиксированным числом аргументов. Тем не менее, я понимаю, что некоторые директивы формата (в частности, ~/ приходят на ум) потенциально могут быть использованы для ввода вызовов функций, делая этот подход по своей сути небезопасным.Безопасная формулировка директив формата в Common Lisp

read При использовании для синтаксического анализа данных в Common Lisp, язык обеспечивает *read-eval* динамическую переменную, которая может быть установлен в nil, чтобы отключить #. инъекции кода. Я ищу что-то подобное, которое предотвратило бы инъекцию кода и вызовы произвольных функций внутри директив формата.

ответ

4

Если пользователь не может ввести пользовательский код, а только форматировать строки, то вы можете избежать проблем print-object. Не забудьте использовать with-standard-io-syntax (или его собственную версию) для управления точным видом вывода, который вы создадите (подумайте о *print-base*, ...).

Вы можете сканировать входные строки, чтобы обнаружить наличие ~/ (но ~~/ действительно) и отказаться от интерпретации формата, который содержит черные списки. Однако некоторые анализы сложнее, и вам может потребоваться действовать во время выполнения.

Например, если строка формата искажена, вы, вероятно, получите ошибку, которую необходимо обработать (также вы можете дать плохие значения ожидаемым аргументам).

Даже если пользователь не является вредоносным, вы также можете иметь проблемы с итеративных конструкций:

~{<X>~:*~} 

... никогда не останавливается, потому что ~:* перематывает текущий аргумент. Чтобы справиться с этим, вы должны подумать, что <X> может или нет напечатать что-либо. Вы могли бы реализовать обе эти стратегии:

  • есть тайм-аут, чтобы ограничить время форматирования принимает
  • имеют основной поток охвата конца-файла при записи слишком много (например, запись в буфер строк).

Могут быть другие проблемы, которые я сейчас не вижу, будьте осторожны.

+1

Спасибо. Я даже не думал о бесконечных проблемах с циклом. С такими проблемами я, вероятно, в конечном итоге напишу свой собственный микроязык для спецификаторов формата, а не пытаюсь настроить «формат». –

+0

@SilvioMayolo Это тоже хороший подход. Но найдите время, чтобы узнать, существуют ли другие форматы: я думаю о 'cl-interpol', но могут быть и другие. Удачи! – coredump

+1

Очень хороший момент о конструкциях итераций! –

3

Это не только ~/, о котором вам нужно будет беспокоиться. Довольно красивая функциональность принтера имеет множество возможностей для расширения кода, и даже ~ A может вызвать проблемы, поскольку объекты могут иметь методы на print-object. НАПРИМЕР,

(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 

Я думаю, вы должны определить для себя, какие директивы безопасны, используя любые критерии вы считаете важными, а затем включают в себя только те.