Безопасность данных Lisp / проверка - PullRequest
7 голосов
/ 08 июня 2010

Это действительно просто концептуальный вопрос для меня на данный момент.

В Лиспе программы - это данные, а данные - это программы. REPL делает именно это - читает и затем оценивает.

Так как же получить безопасный ввод от пользователя? Очевидно, что это возможно - я имею в виду viaweb - теперь магазины Yahoo!

Ответы [ 5 ]

16 голосов
/ 08 июня 2010

REPL обозначает Read Eval Print Loop.

(loop (print (eval (read))))

Выше это только концептуально, реальный код REPL намного сложнее (с обработкой ошибок, отладкой, ...).

Вы можете читать все виды данных в Лиспе, не оценивая их. Оценка - это отдельный шаг, независимый от чтения данных.

В Лиспе есть все виды функций ввода-вывода. Наиболее сложной из представленных функций обычно является READ, которая читает s-выражения. В Common Lisp есть опция, которая позволяет выполнять оценку во время чтения, но ее можно и нужно отключать при чтении данных.

Таким образом, данные в Лиспе не обязательно являются программой, и даже если данные являются программой, Лисп может читать программу как данные - без оценки. REPL должен использоваться только разработчиком и не должен быть доступен для произвольных пользователей. Для получения данных от пользователей используются обычные функции ввода-вывода, в том числе такие, как READ, которые могут читать S-выражения, но не оценивают их.

Вот несколько вещей, которые НЕ следует делать:

  • используйте READ для чтения произвольных данных. READ для примеров позволяет читать действительно большие данные - ограничений нет.

  • оценка во время чтения ('read eval'). Это должно быть отключено.

  • читать символы из ввода / вывода и вызывать их функции символов

  • читать циклические структуры данных с помощью READ, когда ваши функции ожидают простых списков. Прогулка по циклическому списку может на некоторое время занять вашу программу.

  • не обрабатывать синтаксические ошибки при чтении из данных.

6 голосов
/ 08 июня 2010

Вы делаете это так, как все остальные.Вы читаете строку данных из потока, анализируете ее для своих команд и параметров, вы проверяете команды и параметры и интерпретируете команды и параметры.

Здесь нет никакой магии.

Проще говоря, то, что вы НЕ ДЕЛАЕТЕ, это то, что вы не подвергаете свой слушатель Lisp неподтвержденному, незащищенному источнику данных.

Как уже упоминалось, REPL является read-eval-print.@ The Rook сосредоточена на Eval (с разумом), но не стоит сбрасывать со счетов READ.READ - ОЧЕНЬ мощная команда в Common Lisp.Читатель может оценить код сам по себе, прежде чем вы даже получите «eval».

НЕ подвергайте READ чему-либо, чему вы не доверяете.

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

4 голосов
/ 10 июня 2010
  1. Создайте свой собственный читаемый файл и заполните его необходимыми хуками: SET-MACRO-CHARACTER, SET-DISPATCH-MACRO-CHARACTER и др.
  2. Свяжите READTABLE со своим собственным читаемым файлом.
  3. Свяжите READ-EVAL с нулем, чтобы предотвратить #. (может не понадобиться, если шаг 1 выполнен правильно)
  4. READ

Возможно, что-то еще.

Также есть хитрость в интернировании символов во временном пакете во время чтения.

Если данные не в LL (1) -й, просто напишите обычный парсер.

2 голосов
/ 08 июня 2010

Это смертельный вопрос, и я подумал о том же, когда читал про Лисп. Хотя я не сделал ничего значимого в LISP, поэтому мой ответ очень ограничен.

То, что я могу вам сказать, это то, что eval() противно . Есть поговорка, которая мне нравится: «Если eval - это ответ, значит, вы задаете не тот вопрос». --Unknown.

Если злоумышленник может контролировать данные, которые затем оцениваются, у вас есть очень серьезная уязвимость при удаленном выполнении кода. Это можно смягчить, и я покажу вам пример с PHP, потому что это то, что я знаю:

$id=addslashes($_GET['id']);
eval('$test="$id";');

Если вы не выполняете добавление косой черты, злоумышленник может получить удаленное выполнение кода, выполнив следующее:

http://localhost?evil_eval.php?id="; phpinfo();/*

Но косые черты добавления превратят " в \", таким образом не давая злоумышленнику "вырваться" из "данных" и иметь возможность выполнять код. Что очень похоже на инъекцию sql.

0 голосов
/ 09 июня 2010

Я нашел, что этот вопрос вышел спорным.Eval не будет оценивать ваш ввод, если вы явно не попросите его.Я имею в виду, что ваш ввод будет восприниматься не как код LISP, а как строка.

Не потому, что ваш язык имеет мощную концепцию, такую ​​как eval, что он не "безопасен".

Я думаю, что путаница возникла из-за того, что SQL фактически обрабатывает входные данные как [часть] SQL.

(query (concatenate 'string "SELECT * FROM foo WHERE id = " input-id))

Здесь input-id оценивается механизмом SQL.Это потому, что у вас нет хорошего способа написания SQL или чего-то еще, но дело в том, что ваш вклад становится частью того, что оценивается.

Так что eval не принесет вам небезопасности, если вы не используете его глазамизакрыто.

РЕДАКТИРОВАТЬ Забыл сказать, что это относится к любому языку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...