Разбор, защита выражения python перед передачей его в eval () - PullRequest
4 голосов
/ 14 января 2010

Я хочу получить ввод от пользователя, например, foo() > 90 and boo() == 9 or do() > 100 и использовать eval на стороне сервера для оценки этого выражения.

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

PS: входные данные поступают с веб-страницы

Спасибо

Ответы [ 4 ]

3 голосов
/ 14 января 2010

По сути, единственный способ сделать это - разобрать его самостоятельно. Вы перемещаетесь по дереву разбора, чтобы гарантировать, что каждая часть находится в белом списке совершенно безобидных и безопасных операций, что делает все выражение безопасным по построению. Ответ Неда Батчелдера - это (простая) форма этого. После этого вы можете передать его eval(), но какой в ​​этом смысл? Вы можете вычислить значение каждого подвыражения как часть проверки (это особенно хорошая идея, потому что это делает ваш анализатор устойчивым к изменениям синтаксиса Python и т. Д.). Этот белый список должен быть очень маленьким, и есть много вещей, которые вы можете считать нормальными, но это не так (например, оператор общего вызова; функция getattr). Вы должны быть очень осторожны.

Черный список абсолютно исключен (например, предложение «отклонить подозрительные записи»). Откажитесь от всего, что не очевидно хорошо. Если вы этого не сделаете, это будет тривиально обойти ваш фильтр и дать выражение, которое делает что-то плохое, исключая маловероятную вероятность того, что ваш код лучше, чем любой другой черный список фильтров для Python, когда-либо созданных.

Были попытки ограничить выполнение Python, одна из них печально известна и теперь отключена (потому что она не работает) rexec модуль (и компания), а другая - песочница PyPy . Этот второй вариант не делает то, что вы просили, но, безусловно, стоит рассмотреть. Это, вероятно, то, что я бы использовал - это просто означает, что это будет не так просто, как eval(safematize(user_input)).

1 голос
/ 14 января 2010

Возможно, самой простой проверкой было бы посмотреть на все слова в выражении и сравнить их с белым списком. Отклоните выражение, если любое из слов отсутствует в белом списке.

import re

expr = "foo() > 90 and boo() == 9 or do() > 100"
whitelist = "and or foo boo do".split()
for word in re.findall(r"[a-zA-Z_]\w+", expr):
    if word not in whitelist:
        raise Exception("Warning! Warning!")

Это работает, потому что у вас есть ограниченный домен, в котором вам нужно, чтобы пользователи могли выражать себя, а также потому, что я не думаю, что есть способ нанести ущерб с помощью eval без использования идентификаторов.

Вы должны быть осторожны, чтобы ваш белый список не содержал случайно вредоносные идентификаторы Python.

1 голос
/ 14 января 2010

Вам необходимо заблокировать входной формат, иначе это будет зияющая дыра в безопасности.Либо реализуйте полноценный синтаксический анализатор, как предполагает lpthnc, с разумным набором операций (но не более), либо, по крайней мере, используйте регулярное выражение (или несколько шаблонов регулярных выражений в соответствующей иерархии и / или цикле), чтобы вырезать распознанные шаблоны,и отклонить подозрительные записи как «не разрешенные».

1 голос
/ 14 января 2010

более безопасный способ сделать все на заднем плане. Пользователи просто вводят необходимые параметры. Например, вы можете предложить им ввести числовые значения для foo (), boo () и do (). Затем на заднем конце передайте эти значения соответствующим функциям для выполнения вычислений.

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