шаблоны с php-кодом: как обезопасить

carfax

Guest
шаблоны с php-кодом: как обезопасить

Условия задачи:
Есть движок, использующий в качестве шаблонов php-шные файлы, которые подцепляются include'ами там, где надо. То есть, шаблон может содержать php-код, который будет исполняться при подключении шаблона.

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

Проблемы возникают тогда, когда надо дать возможность постороннему человеку (дизайнеру) править шаблоны через веб интерфейс движка. Надо каким-то образом сделать так, чтобы дизайнер мог вставлять в шаблоны переменные (<?=$var1?>) и какой-то простой код, но при этом не мог использовать потенциально опасные функции, открывающие файлы или ползущие в базу без спроса.

Исходим из предположения, что дизайнер может быть злоумышленником, хорошо шарящим в php.

Пока, мне пришло в голову только одно: грубо вычишать шаблон от опасных функций перед сохранением файла на диск.

Примерно так:
PHP:
$template=str_replace("mysql_fetch_array", "censored", $template);
Какие еще могут быть варианты?

Использовать smarty и т. п. не предлагать.
 

_RVK_

Новичок
какие умные у вас дизайнеры :)
А вообще, имхо, нужно не запрещать опасные функции, а разрешить безопасные и нужные. Таких может с десяток наберется, за глаза хватит.
 

carfax

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

А так, да - с точки зрения безопасности принцип "завпрещено все, кроме того, что разрешено" правильнее. Но вопрос в том, как это реализовать на практике?
 

Кром

Новичок
carfax
Сделай массив разрешенных функций. И тем же регулярным выражением, проверяй на соответствие. Остальное удаляй.
 

carfax

Guest
Хм...
Мы имеем некий текст, содержащий HTML и PHP-код...
Что-то я как-то смутно представляю, как из этого текста убрать все, кроме разрешенных PHPшных конструкций.

Ну, допустим отделить PHP от HTML - это не сложно. А вот как из кусков кода поубирать все лишнее?

Берем примитивный вариант, когда нам надо разрешить только echo, include() и if () {} else {} + свободное именование переменных. Как поубирать остальное?

Чё-то как-то со скрипом у меня в голове эта задача формализуется.

Вариант: разбираем код на слова, отсеивая все, что начинается с '$'. Затем убиваем те слова, которые не входят в список разрешенных...

Пните меня в нужном направлении, что-то я совсем торможу.
 

Кром

Новичок
>А вот как из кусков кода поубирать все лишнее?
[m]preg_replace[/m] + регулярное выражение.

Впрочем, если здраво подумать, луче тебе вообще отказаться от PHP в шаблоне. Это будет безопаснее, учитывая, то что ты пока не отдаешь себе отчета, как себя обезопасить.
А что ты разрешаешь использовать include(), вообще может привести к печальным результатам.
 

carfax

Guest
Грустно это... Что ж. Бум думать.

Пока, наверное, придется запретить все, кроме вставки переменных в шаблон.
 

HEm

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

еще вариант - посмотреть на смарти и сделать список своих функций, вызывать их не через <? func(); ?> а через { func(); } - таким образом использовать функции из php не получится
 

Crazy

Developer
Автор оригинала: HEm
Можно проходить по тексту str_replace-ом, заменяя все вызовы запрещенных функций на свою пустую заглушку
$foo(1) -- это разрешенная функция или нет?
 

carfax

Guest
HEm
Изначально, такая мысль и была. Вопрос в том, какие функции надо блокировать. С доступом к Mysql понятно - режим все, что начинается с myslq_, а вот что делать с файловым доступом и прочим прибабахам, с помощью которых можно систему хакать? Тут надо конкретно список составлять... И я побаиваюсь, что упущу что-то, что упускать не стоит. :)

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

Что еще?
 

Crazy

Developer
Подход принципиально порочен. Нужно не избирательно запрещать, а избирательно разрешать.
 

_RVK_

Новичок
carfax
нет нужды убивать все лишнее. Нужно просто сказать что такая-то фцнкция запрещена.
Не нужно запрещать конструкции. Они ничем не опасны (кроме include/require пожалуй).

ИМХО, твой вариант с использованием пхп в шаблоне, в твоей ситуации неоправдан. Тут лучше использоватвторой вариант, предложенный вариант HEm.
 

HEm

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

В итоге напишешь тот же smarty но легче по функц. возможностям и ущербнее с точки зрения безопасности (там все-таки много народу отлаживает/тестирует а тут ты один)
 

carfax

Guest
Конечно, смарти переписывать не буду... если уж все будет так серьезно, то просто этот самый смарти и прикручу.

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

Согласен на счет своих функций. Написать функцию с простым форматом вызова <?inctpl('login_form','profile_link')?> и научить функцию подключать то или другое в зависимости от статуса пользователя.

Пока останавливаюсь на этом варианте.

Теперь реализация. Что, если сделать так:
В шаблоне переменные оформляем так - {variable}, функции по-другому - #func()#, допустим.

Перед сохранением шаблона проделываем такие шаги:
1. Вычищаем из текста "<?" и "?>" (запрещаем пхп)
2. Заменяем "{" -> "<?=$" и "}" -> "?>"
3. Заменяем все известные нам псевдо-функции #func1(....)# на реально существующие - <?inctpl()?>.

Перед открытием шаблона на редактирование, делаем обратные преобразования:
1. Заменяем "<?=$" и "?>" на "{" и "}"
2. Заменяем известные нам функции "<?inctpl(...)?>" на "#func1(...)#"
3. Отдаем этот текст в веб-интерфейс.

Прокатит такой вариант?
 

Demiurg

Guest
Интересно, а что у тебя сам движок делает ?
и еще, как можно запросоми к базе поломать другой сайт?
 

_RVK_

Новичок
carfax кажется ты все усложняешь.... перед сохранением кода регами просматриваешь код на наличее конструкций foo($var1...); и сравниваешь их с разрешенными функциями. если такой функции нет в твоем списке то ругаешься. Это для варианта с кодом php.
Вариант с заменой своих функций на код, перед сохранением начем не отличается(в лучшую сторону) от первого варианта...
Третий вариант типа Smarty. Есть смысл его реализовать самостоятельно, тк код получится легче и опыт получишь неоценимый.
 

carfax

Guest
Demiurg
Если очень интересно, могу показать. Демо-версии я еще не оформил, но могу сделать копию существующего сайта для опытов.

Поломать можно потому, что:
Движок поддерживает n-ное количество сайтов на одном комплекте скриптов. По сути все просто: головной скрипт смотрит HTTP_HOST, лезет в табличку и узнает, в какой базе хранятся данные запрошенного сайта. Естественно, в этой табличке есть пароли доступа к базам сайтов.

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

-~{}~ 15.03.04 10:45:

HEm
как дезигнеру в тексте написать скобочку } ?
Гм... а в чем проблема?
 

Demiurg

Guest
Я не хочу смотреть демо-версии. Мне просто интересно на словах, что делает движок.

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