2007-07-29

Zend Framework 1.0.0 - как бы я строил начальный каркас

Не знаю, на сколько я прав в этом вопросе, но я не думаю, что совершил много грубых ошибок в проектировании. Тех, кто далёк от архитектуры Model-View-Controller попрошу остановиться и ознакомиться где-либо с этой идеологией.

Итак, для установки Zend Framework 1.0.0 на сервер не нужно никаких особых шаманств с бубном. Всё что вам нужно, это соответствовать требованиям Zend Framework. Там нет ничего сложного - PHP 5.1.4 (рекомендуется 5.2.2), SPL и, возможно, некоторые extensions, если вы будете использовать определённые компоненты Zend Framework.

Структура каталогов для быстрого старта с Zend Framework о которой пойдёт речь далее.

(далее…)

PHP, Web, Zend Framework — Sergej Kurakin @ 03:09
Таги: , , ,
2007-07-18

Первые 8 часов с Zend Framework 1.0.0

Провёл с Zend Framework 1.0.0 около 8 часов. Результат: всё-таки я это дело запустил, подключился к базе, сделал 404 страницу, сделал форму регистрации. Подводных камней куча. Мануал по Zend Framework и примеры желают лучшего. По сравнения с Ruby on Rails стартовать реально сложно - примеры все написаны под разные версии до 1.0.0 и очень часто отличаются структурой.

Первое и самое лёгкое в процессе, это установка: всё просто - скопировал в папку, в include_path закинул и всё, можно пользоваться. Подробности - Introduction to Zend Framework, Installation.

Далее - контроллеры. С ними Quick Start прошёл тоже быстро. Фактически всё из Quick Start прошло без проблем, кроме 404 страницы. Всё сделал как они описали, но не заработало. Код я видимо взял из примера и у меня пробрался throwExceptions в режиме true, как только я понял что к чему, всё заработало. То, как устроена обработка 404ой ошибки с Zend_Controller_Plugin_ErrorHandler мне понравилось. Пока не разобрался с возможностью самому задавать правила роутинга, но это наверняка мелочь уже.

Что меня на данном этапе удивило - это то, что нет единой принятой структуры каталогов, как у Ruby on Rails. Конечно, в Quick Start есть пример, но всё это сделано руками и где-то в мануале, а на это статью не сразу натыкаешься. Я бы сказал не хватает Creating a weblog in 15 minutes - с Ruby on Rails я как-то проще начинал.

Итак, так как я уже разобрался с контроллерами и акшинами, я перешёл к конфигам. WOW! и никаких конфигов тоже небыло. Если надо - пожайлуста, делай сам, из массива, из .ini или из .xml. Где и как будет лежать - наши/ваши проблемы.

Конфиг есть, пора бы и за базой поработать. Обилие возможностей для работы казалось бы не может не радовать. Zend_Db_Select, Zend_Db_Table, Zend_Db_Table_Row. Осилил я Zend_Db_Table и Zend_Db_Table_Row. Часа 3 потратил на то, чтобы загрузить модели, ну или то, что в Zend Framework называется моделью. Оказывается, не смотря на то что в структуре примера есть папка application/models у меня их автоматом не грузит. Как их грузить я вообще не нашёл, поэтому тупо сделал им require_once и всё вроде заработало.
Пока не нашёл способа, куда вводить их моделям валидацию, как в Ruby on Rails, видимо, в Zend Framework всё реализовано по другому. Особо хакать исходники времени небыло, я оставил всё как есть. Потом меня приятно удивил метод save - в случае ошибки, он падает с Exception. Я ожидал что он элементарно будет возвращать true/false и всё. Ладно - обошли это проблему пока, и особых решений этой проблемы я пока не видел, зато видел где-то в их wiki много try { [...] } catch { [...] } при работе с их моделями.

Скажу честно - впечатления пока никакие. Я ожидал намного больше и со стороны документации и со стороны примеров. да и со стороны самого Zend Framework 1.0.0 я ожидал куда более простую систему, чем увидел. Может это и не верное первое впечатление, но именно оно отталкивает меня от использование Zend Framework в работе и заставляет меня использовать личные разработки.

PHP, Web, Zend Framework — Sergej Kurakin @ 16:43
Таги: , , ,
2007-06-22

SimpleActiveRecord 0.0.2

Сегодня я запустил в свет SimpleActiveRecord 0.0.2.

Что нового?

  • Ввёл тесты для магических методов, которые естественно, он завалил, и их я тут-же поправил.
  • Плюс ко всему добавилась проверка на то, NULL или не NULL значение поля по умолчанию если оно пустое должно быть. Теперь, если сделать unset(); для поля и у него NULL = YES в структуре базы - оно после сохранения станет NULL а не пустой строкой. Присвоение значения по умолчанию при unset();
  • Разделил тесты между простыми методами и методами создания записей в базе.
  • Заложил возможность на проверку типов данных. Уже сейчас он проверяет значение поля типа SET на соответсвие сета.

Что для меня важного в этом классе?

  • Он сам узнаёт название таблицы в конструкторе.
  • Сам подгружает имена полей, их типы и значения по умолчанию.
  • Я приучаю себя всегда документировать код.
PHP, SAR, Web — Sergej Kurakin @ 01:25
2007-06-19

Маленький кусочек OpenSource

Так как каждый из нас, программистов, постоянно экспериментирует и старается развивать себя и свои возможности и знания, я регулярно пересматриваю разные чужие OpenSource решения, пишу какие-то свои маленькие скрипты, библиотечки, классы, которые иногда даже не выходят за пределы localhost или превращаются в коммерческие продукты dip.:studio - их выкладывать на обзор всей публики не целесообразно, но чем-то поделиться хочется.

Так вот, в свободное время, дома, я начал писать маленький простенький ActiveRecord. Пока могу показать только версию SimpleActiveRecord 0.0.1. В пакет входит сам класс, быстро сгенерированная документация на phpDoc (там есть примеры использования), маленький набор тестов Unit Тестов на phpUnit. Всё это чудо рассчитано на PHP 5.2.3.

Я не буду утверждать, что это супер-оригинальное или гениальное решение, просто это мой взгляд на быстрою и простую реализацию ActiveRecord в версии 0.0.1. Если у кого либо есть конструктивные комментарии - пишите (модерация включена, пересматриваю регулярно раза 2 в день).

PHP, SAR, Web — Sergej Kurakin @ 23:29
2007-04-23

Как, бывает, хранят пароли

Я, пока, опущу ту вкусную часть, как при помощи SQL-Injection можно получить пароли пользователей, но желающие могут самостоятельно прочесть IV раздел мануала о Безопастности - SQL Injection . И расскажу о самой неприятной (ок, не всем не приятной) привычке - открытых паролях и том как их хранят в других случаях.

Итак, первый и самый простой случай, когда пароли хранятся в таблице (название не имеет значения, но очень часто это бывает таблица users, admins или members, возможны разные префиксы), в поле password (обычно нужные поля очень легко узнать по форме регистрации или логина). Оно очень приятно, когда у сайта есть уязвимость ввиде SQL-Injection - вытянуть пароль и логин нужного вам пользователя не составит никакого труда. Время, нужно на поиск, занимает от 10 минут до нескольких часов - всё зависит от мастерства и фортуны (но не стоит исключать человеческий фактор). Кстати, если базу уводят (физический дамп с сервера), создателям скажут “спасибо”. Такие разработчики обычто оставляют незащищённый phpMyAdmin на сервере в легко доступном месте, а иногда оставляют SQL-Injection в скрипте логина в CMS. Вы конечно скажете - бред, не может быть, но всё-же такие случаи встречаются в моей практике и не раз.

Более сложный вариан для взломщиков - когда пароли хешируют. Обычно, встречаются варианты когда пароль просто хеширую при помощи md5 или других функций. Хотя тут, народ исхитрился иметь небольшие базы готовых хешей. Значит и тут пароли могут пострадать - вопрос размера базы хешей и то, какой это хеш. Конечно, все пароли не раскроют. Часто в базе - словари, фразы, а всякие “kld8jSkhYakKd772″ там наврятли будут - всё зависит от размера базы, вашей удачи и, иногда, от теории вероятности (про коллизию не забываем, да).

Итак, в резюме, получается, что с паролями излишняя параноидальность вам/нам не помешает. Если вы поманипулируете с паролями пользователей (да и администраторов) - вам это не повредит ни в коем случае. Сделать пару SALT, докинуть чего из “логина”, добавить битовую операцию, потом сделать base64 енкодинг и только потом хеш - это наверняка затруднит восстановление ворованного пароля.

А что вы посоветуете?

PHP, Security, Web — Sergej Kurakin @ 00:04
2007-04-21

Что я знаю о register_globals

Постоянно сталкиваюсь с серверами, где по умолчанию register_globals = On. Да, мне ничто не мешает взять .htaccess и отключить: php_value register_globals Off или написать письмо администратору сервера. Однако, иногда и сам забываешь о той угрозе, которую несёт в себе register_globals = On.

Для того, что-бы воспользоваться чем-то, что даёт вам register_globals = On, нужно либо иметь на руках исходники скрипта, либо быть очень счастливым с…м сыном (ну ещё есть шанс, что ошибки, выбрасываемые PHP вам помогут). Естественно, речь идёт о Global Scope.

На днях я перебирал один маленький сайтик, где PHP используется только для того, что бы можно было удобно и быстро подключить хедер и футер, меню и для страниц легко менять тайтл и мета данные. Такой классический сайт из учебника, плюс несколько наворотов, которые позволяют кешировать сайт на стороне клиента так, как будто это статически HTML. Теоретически, если отключить expose_php и сделать ServerSignature Off, а ServerTokens Prod мало кто догадается, что это PHP.
И нашёл я там одну переменную, которая отвечала за подключение отдельного CSS для страницы. Она была задекларированна не во всех файлах, а толxко там, где требовался дополнительный CSS файл. Именно в тех файлах, где эта переменная не была установлена, её можно было установить при помощи GET, POST или COOKIE (ведь мы помним о variables_order). Плюс никакой фильтрации. Идеальное место для XSS type1 атаки. Но для такой атаки имя переменной нужно знать.

Есть ещё такой стиль программирования, когда массивы никто не декларирует, а сразу к ним обращается. Я имею ввиду, что некоторые программисты не пользуются таким выражением: $arr = array ();, а сразу выполнят присваивание: $arr[] = ’some value’;. Опять же через GET, POST или COOKIE в таком случае можно передать первые ключи для массива $arr. И тогда сколько таких переменных есть у них, которые можно поменять, зная их имена?

Вроде и нет ничего страшного, действует только на Global Scope, надо знать название переменной, но вы не можете гарантировать, что копия сайта е попала в руки мальчишам-плохишам. Так, однажды, получив исходники одной CMS, можно досконально изучить её код, найти уязвимые места, а потом вскрыть этак сайтов 10-15 с одной и той-же ошибкой. Именно так однажды случилось с CMS моего знакомого: CMS решал, человек залоглен или нет, опираясь на онду переменную $admin_id. Стоило сделать запрос admin.php?admin_id=1 и коробочка раскрылась и даже не смотря на то, что этот $admin_id должен был придти из сессии - н там не был установлен (я взял новую сессию) и скрипт пощитал, что всё впорядке и можно пользоваться.

Короткое резюме: пишите свои проекты с учётом register_globals = Off; если вы уверены, что вами написанный проект отлично работает с register_globals = Off, а на сервере register_globals = On - отключите register_globals, так как в редких случаях это может вызвать неадекватное поведения вашего проекта; если вам приходиться работать со скриптами, которые требуют register_globals = On (только в том случае, если это необходимо), будьте предельно бдительны, не сделайте глупых ошибок, связанных со свойством register_globals = On, а также проведите аудит скрипта на возможные ошибки - вы последний, кто его редактировал и все бочки посыпятся на вас.

PHP, Security, Web — Sergej Kurakin @ 14:45
2007-04-20

Заметки о загрузке файлов с PHP

Знаете, я не специалист по безопастности, но постоянно встречаюсь с элементарными проблемами любого WEB-программиста. А за последнюю неделю в жизни/работе призошло не мало изменений, связанных с безопасностью. Первое что очень сильно повлияло - это PHP Security conference, на котором показали на сколько бывают глупы создатели сайтов. Второе - это то, что я уже проверить и накопать на окружающих сайтах и своём коде.

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

Элементарная форма. Элементарный скрипт. Для того, что-бы нормально обработать картинку на “любом” сервере, её в начале нужно двигать в свой каталог на сервере. Чаще всего это где-то внутри DocumentRoot, и в редких случаях вне его. Почему? А никто не отменял случаев с включенным open_basedir. И вроде нет ничего опасного в том, что я написал, но, если файл попал в DocumentRoot - его можно соответственно вызвать броузером. А если вы не проверили что это за файл - могут быть проблемы. Ведь могли загрузить и PHP или Perl скрипт, в котором может быть бог знает что.

И я не буду скрывать, что я купился на этой форме. Да, тут я лажанулся. Я понадеялся на getimagesize. Оказалось - зря. В первую очередь нужно проверять расширение файла в массиве $_FILES['userfile']['name'] и ещё перед выполнением move_uploaded_file. И не забудьте провериться перед этим с is_uploaded_file.

Вот на расширении файла я и попался. Я этим (по непонятным мне причинам) очень сильно принебрёг и понадеялся на функцию getimagesize. А вот она то и подвела. Оказывается (установлено экспериментальным путём на локальном PHP версии 4.4) - при загрузке файла с расширением .php (помните, я этим принебрёг), если в этот файл всунуть первые 128 байт из PNG файла, getimagesize считает что это картинка. Соответственно PHP файл попал на сервер, а что дальше бывает, я вам рассказывать не буду.

Некоторые говорят, что нужно ещё проверять $_FILES['userfile']['type'], но доверять ему нельзя - это данные, которые нам посылает клиент и они могут быть легко потделаны на строне клиента.

Загружая файл, не рекомендуют полностью доверят и $_FILES['userfile']['name'] - только профильтровав, или только расширение. Если же его прямо вписать, возможна атака путём подделки имени файла (скажем впишут вам ../../../index.php, а если у вас suEXEC или su_php можно и пострадать). Причём, они (создатели PHP) даже не подумали это дело отфильтровать автоматически, хотя в примере Validating file uploads создатели мануала об этом подумали (сам пример на данный момент мне не понятен).

Если разобрать пример Validating file uploads, а мне он виден вот таким совсем не понятно, каким образом они установили что происходит “Possible file upload attack!”? Ведь файл будет сдвинут в каталог /var/www/uploads/, а если он не будет сдвинут - следовательно, либо нету прав на это, либо исходный файл пропал. По моему, там должна была функция is_uploaded_file, а move_uploaded_file уже потом.

Итак, короткое резюме: проверять файл по разрешению и разрешать загружать только те файлы, которые 100% не будут выполнены сервером как скрипты (я бы разрешал загружать только картинки); не доверять $_FILES['userfile']['name'], проверять и фильтровать её, если используете; если файл переноситься во временное место для обработки, постарайтесь это место либо держать вне DocumentRoot, либо закрыть его при помощи .htaccess; не доверять вообще $_FILES['userfile']['type']; пользуйтесь функциями is_uploaded_file и move_uploaded_file; проверяйте и перепроверяйте параметры.

Если у вас есть комментарии на эту тему, советы или замечания какие - пишите.

PHP, Security, Web — Sergej Kurakin @ 20:41
2007-04-17

PHP Security conference в Каунасе

Итак, прошёл PHP Security conference или PHP Security training в Каунасе.

XSS, SQL-Injections, Code Executions, Code Inclusions, Using google to find a Target, Shell Executions, Intranet Exploits, Output Encodings hacks и прочие вкусные вещи прошли огромным кол-вом через мои мозги. Часть осела, часть знал, о части даже не подозревал.

Johann-Peter Hartmann очень правильно подобрал материал, с немцам присущей пунктуальностью провёл не только лекции, но и hands-on курс с примерами взлома сайтов местных. 30 минут на взлом, несколько минут на поиск потенциальных мест для взлома, анализ кода (были даны примеры кода из зала, а он показал как надо это делать).

Вообще, очень много вещей в безопастности, связанной с PHP проектами, завязано на самом языке, а так-же на особенностях броузеров. Очень сильно убило то, как некоторые куски абсолютно не валидного кода, с огромными ошибками, отрабатывают броузеры, то как себя ведут броузеры и как их можно поймать с неуказанными чарсетами. Я об этом даже не подозревал.

Были затронуты вопросы безопастности на уровне сервера (в смысле Apache, Linux/Unix конфигурации), но очень поверхностно, так как это от части не совсем забота программиста.

Вообще, очень полезная инвестиция, как денег фирмы, так и личных. Очень прочистило мозг. Очень! Чаще бы так.

HTML, JavaScript, PHP, Web — Sergej Kurakin @ 21:19