Предварительная фильтрация PHP кода - как разрешить только алгоритмические команды?

xintrea

Новичок
Предварительная фильтрация PHP кода - как разрешить только алгоритмические команды?

Здравствуйте.

Вот у меня тут есть такой вопрос, не совсем обычный...

Можно ли (и если можно, то каким образом) сделать так, чтобы на сайте с языком PHP
существовал раздел, который бы позволял любому пользователю добавлять PHP-код
и сразу _выполнять_ его. Причем от языка PHP нужно разрешить только "алгоритмическую"
часть, то есть разрешить в коде использовать только

- работу с переменными
- работу с массивами
- функции, определенные в текущем коде
- вывод print или echo
- (опционально) математические функции

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

Так вот сам вопрос - можно ли такую вещь как-нибудь сделать?
Конечно, понятно, что такой раздел на сайте - огромнейшая дыра и потенциальная угроза,
причем ещо какая. Но вот может быть всеже есть возможность сделать такую вещь
без сильного нарушения безопасности?

Из возможных путей я пока вижу несколько -

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

- Проанализировать код на наличие описания функций (Это более-менее просто).
Просканировать код и определить все места вызова функций (кстати, как правильно
это сделать?). Если вызывается неописанная функция, не разрешать код к запуску...

- Комплексный подход средствами UNIX и PHP. Выделить директорию, выход из которой
для php скриптов невозможен (это вообще реально сделать?). Назначить права для
предотвращения записи внутри директории с такими скриптами. Это ограничит файловые
функции скриптов пользователей. Обрезать опции по самые яйца в php.ini (а что там можно
реально обрезать?).

(Дополнительные условия - все должно работать на обычном UNIX хостинге без
экзотических конфигураций.. То есть, иметь два транслятора php или два файла
php.ini -для обычной части сайта и для "защищенной" - ни один админ не будет с
этим ковыряться.)


У кого есть какие соображения по этому поводу? В каком направлении копать?
 

kvf77

Red Devil
xintrea
придумай мета-язык, то есть свой синтаксис, а потом парси его в код сам - например так смарти делает
 

garlian

Новичок
kvf77 прав я бы тоже так делал. Придумал свои обозначения, а потом можно использовать фунции замены(например preg_replace()) на php язык.
 

xintrea

Новичок
Эээ, идея хороша, только есть одно но...

Синтаксис у исходника должен быть PHP-шный. То есть придумывать и вводить самодельные обозначения нельзя.

Автор оригинала: kvf77
придумай мета-язык, то есть свой синтаксис, а потом парси его в код сам - например так смарти делает
Кстати, что есть "смарти" ?
 

xintrea

Новичок
Автор оригинала: Макс
Можно [m]tokenizer[/m]-ом попробовать парсить код.
Ну это всего лишь лексический анализатор. Он конечно облегчает работу, но... Вот если б в PHP был еще и синтаксический анализатор, который выдает синтаксическое дерево, тогда можно былоб шустро разделываца с "неправильным" кодом.

Я вот было подумал сделать такую вещ - в PHP есть функция get_defined_function(), которая выдает список всех функций, работающих в текущей конфигурации PHP.

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

То есть для всех функций сделать так

function fopen {return;}

Проблемма в том, что переопределить системные PHP функции невозможно. Я то думал, что в первую очередь будут искаться функции внутри скрипта, ан нет. Выдается ошибка "Cannot redeclare...". Как обойти это я не знаю.

Вопрос - так, как я рассказываю, сделать принципиально нельзя? Или есть всеже путь?
 

Frol

Новичок
The tokenizer functions provide an interface to the PHP tokenizer embedded in the Zend Engine. Using these functions you may write your own PHP source analyzing or modification tools without having to deal with the language specification at the lexical level.
что не ясно?
 

xintrea

Новичок
Автор оригинала: Frol
...Using these functions you may write your own PHP source analyzing or modification tools without having to deal with the language specification at the lexical level.
Что не ясно?
Не ясно, как лексическим анализатором, а именно о нем идет речь - "at the lexical level", проверить "на допустимость" команду PHP языка. Он выдергивает только лексемы, и все. Он даже не проверяет правильность вложений выражений. А чтобы раздраконить конструкцию команды, нужен синтаксический анализатор.
 

Макс

Старожил PHPClub
xintrea
ты хочешь инструмент который бы все за тебя делал ?
Предварительно код можно проверить "php -l script.source.php"
Есть еще [m]parsekit[/m] - может поможет.
 

xintrea

Новичок
Спасибо всем ответившим. Работа пошла. :)

-~{}~ 06.03.06 22:15:

Кстати еще вопрос...

Вот имеем массив токенов, полученный через token_get_all().

Я расковыриваю этот массив, и нахожу, например, недопустимую функцию.

Вопрос - как однозначно определить, в какой строке _исходника_ была найдена эта недопустимая функция? Ведь в массиве токенов нет никакой справочной или синхронизирующей информации, в какой строке находится тот или иной токен.
 

xintrea

Новичок
Автор оригинала: Frol
предлагаю почитать комментарии к функции.
Да, точно. Нашел. Мой английский не позволяет быстро понимать о чем идет речь.. Проверил - оно работает! :)

Впринципе теперь ничего не мешает сделать "открытый доступ к добавлению произвольного кода", за исключением одного вопроса.

Я не настолько хорошо знаю PHP, поэтому спрашиваю..

Вопрос. Существует ли в PHP возможность вызвать функцию не по имени? Точнее, не по стандартному ASCII-имени? То есть может ли потенциальный хакер написать так код, чтоб незаметно для проверяющей программы присвоить например указатель на функцию в переменную, а потом вызвать эту функцию? Причем присвоение указателя замаскировать в виде строки... Или вызвать функцию по какому-то "внутреннему" php-номеру, не вводя ее имя?
 

xintrea

Новичок
Автор оригинала: Frol
PHP:
$var = 'strlen';
echo $var("bla");
Это единственный путь?

Правда переменная может быть еще и частью массива...
Вот так тоже работать будет...

PHP:
$var[1] = 'strlen';
echo $var[1]("bla");
или вместо [] можно писать {}, тоже будет работать...

Еще можно так

PHP:
$var = "strlen"; 
$a="var";
echo $$a("bla");
А еще оказывается можно и такое провернуть

PHP:
$a = `ls /usr/sbin`;
echo $a;

Все, больше возможностей не вижу.

Правильно ли я понимаю, что достаточно сделать, ну пусть три блокирующих правил (пробелы не учитываем)

1. Если после T_VARIABLE идет открывающая скобка "(", то такой код опасный.

2. Если после T_VARIABLE идут открыто-закрытые скобки "[" или "{", а затем открывающая скобка "(", то такой код опасный.

3. Запретить вообще, тупо, обратные апострофы ' (в прямых апостофах или других кавычках последний пример работать не будет). Да и двойные кавычки " тоже запретить вообще. Чтобы работало правило, если надо что-то вывести, то и выводим, без всякого парсинга внутри строки. То есть разрешить только одинарные апострофы.


Этого хватит, или у хакера есть еще путь ?


(Естественно, всякие include, eval, system, passthru, list, array - запрещенные языковые конструкции).

-~{}~ 08.03.06 01:05:

Таки никто не знает? Боюсь, ломанут такой сайт в первый же день... Ведь наверняка ещо дырки остались..
 

HEm

Сетевой бобер
>> list, array - запрещенные языковые конструкции
ха-ха

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

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

xintrea

Новичок
Возвращаясь к старой теме...

Господа, а вот еще вопрос к PHP-гуру.


Вот я смотрю официальную документацию PHP про использование массивов
http://us2.php.net/manual/ru/language.types.array.php

и почему-то не нахожу описание следующей особенности.

По непонятной причине, PHP позволяет оформлять элементы массива
как прямыми скобками [], так и фигурными скобками {}. В документации же
написано только про прямые скобки. То есть, если бы я делал блокировку
опасных конструкций по документации, я бы имел большую дырку
в безопасности.

Пример опасного кода:
PHP:
$var[1] = "strlen"; 
echo $var[1]("bla");
Если возможны обозначения только [] и {}, то такой код я могу определить
и заблокировать. А вот если возможны еще какие-то обозначения,
то будет дыра.

Отсюда вопрос - обозначение элементов массива возможно только
через [] или {} и все? Или есть еще какие-то обозначения? (Доступ
к элементам через функции не рассматриваем).


Далее. Строки.

Согласно документации http://us2.php.net/manual/ru/language.types.string.php
строки можно задавать через

- одинарные кавычки (апостроф),
- двойные кавычки
- Heredoc-синтаксис.

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

Пример.
PHP:
$a = `ls /usr/sbin`; 
echo $a;
Вопрос - а есть ли еще какие способы задать строку? (Не через функцию).
 

SiMM

Новичок
> По непонятной причине, PHP позволяет оформлять элементы массива как прямыми скобками [], так и фигурными скобками {}.
Ноги, видимо, растут отсюда - [m]language.types.string#language.types.string.substr[/m]

> Однако известно, что строку можно задать и через обратный апостроф.
Это не задание строки, а получение результата вызова консольной команды - [m]language.operators.execution[/m]
 

DiMA

php.spb.ru
Команда форума
xintrea
То что ты так долго описывал, называет Безопасный интерпретатор. Для пхп не существует и врядли будет создан. А вот в TCL я им много пользовался, чтобы исполнять опасный код. В безопасном интепретаторе свое пространство имен, функций и по умолчанию отключеню все языковые функции для файловой системы и прочего. А с помощью установки связи в Б.И. TCL можно подключить любые опасные внешние функции языка или ссылки на переменные. Т.е. абсолютно все гибко и настраивается. TCL весьма беден на библиотеки, написан лет 20 назад, но по многим моментам впереди планеты всей. Тоже интерпритируем, как пхп. Так шо не изобретай велосипед, а юзай абсолютно надежные готовые решения. Максимум опасности от Б.И. - зависание скрипта - while (1);

пс. Да, и не надо доказывать мне необходимость изобретать велосипед на пхп. Избавь от такого удовольствия.

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

Ух нифига себе, какие ужасы рассказываешь. Типа если засунуть пхп в сейфмод и от бесправного юзера в винде, то прямо так и жди хака с минуты на минуту :) Бедные хостеры то не знали :)
 
Сверху