Обработка метаданных и цифровое подписывание HTML-форм Дмитрий Котеров архитектор и главный разработчик MoiKrug.ru, компания Яндекс
Что такое метаданные? Данные –то, что ввели array( "lastname" => "Пупкин", "gender" => "m" ) Метаданные –"данные о структуре данных" array( "lastname" => array( "type" => "text", "caption" => "Фамилия", "dbfield" => "p_lastname" ), "gender" => array( "type" => "single", "dbfield" => "p_gender", "elements" => array( "m" => "Муж", "f" => "Жен", ) ) ) Фамилия: Пол: Муж Жен
Типы полей с точки зрения метаданных Текст –,, Файл (закачка) – Единичный выбор – – … Множественный выбор (аналогично) – – … Действие –,
Web- или GUI-приложение Web-приложение –"Размазанность" –Двойная валидация (PHP, JS) –Нет доверия метаданным (неявная структура POST) –Дублирование метаданных в дизайне и обработчике –Косвенный вызов обработчиков GUI-приложение –Централизованная обработка –Непосредственная валидация –"Доверие" метаданным (все в рамках одной оконной формы) –Форма "рисуется" и обрабатывается в едином месте –Мгновенные обработчики кнопок Рисовальщик формы Пользова тель GUI-приложение: форма + обработчики событий Пользователь HTML POST errors Обработчик формы
"Размазанность": неявные зависимости от метаданных Различные компоненты системы –Структура БД –HTML-представление формы –Рисовальщик (код начального заполнения формы) –Обработчик (код приема данных и записи в БД) –Серверный валидатор (PHP) –Клиентский валидатор (JS) Как их объединяют, чтобы обойти проблему –Структура БД –HTML-представление формы + клиентский валидатор –Рисовальщик + обработчик + серверный валидатор
Централизация метаданных Репозиторий метаданныхПодход MetaForm – похож на GUI-формы HTML + JS Рисовальщик + обработчик + валидатор Metadata HTML + Metadata Генератор по явно выделенным метаданным сложность доработки неуниверсальность Рисовальщик + модификатор + обработчик + валидатор БД
MetaForm: шаблон + метаданные Фамилия : Пол: Муж Жен Метаданные объединены с представлением (как в GUI) Автоматическое извлечение метаданных Использование возможностей HTML для привязки заглавия Назначение валидаторов (серверных + клиентских) Назначение произвольных мета- атрибутов Отправка формы "на себя" Обработка HTML "на лету": –Легкость адаптации старых проектов –Совместимость с любыми имеющимися framework-ами –Неизбыточность ("а добавим-ка новое поле")
MetaForm: традиционная обработка Обработка формы: –распаковка метаданных –проверка цифровой подписи –валидация –сохранение сообщений об ошибках –сохранение сообщений в сессии –"редирект на себя" Подготовка метаданных –извлечение метаданных из HTML формы, "чистка" формы –упаковка и цифровое подписывание метаданных –вставка метаданных в hidden- поле Отрисовка формы: –вставка данных из $_POST (FormPersister) –назначение клиентских валидаторов –привязка сообщений об ошибках к полям switch ($m->process()) { // Простой показ формы. case "INIT": $_POST = ; break; // Нажата кнопка. case "имя_кнопки": $meta = $m->getMetadata(); ; ; ; break; // Произошла ошибка валидации } ; ; ; ;
MetaForm: событийная обработка switch-case хорошо подходит при переводе старой системы на MetaForm событийная модель удобна для построения CMF // Контроллер Page class Page { function init() { // Простой показ формы. $_POST = ; } function имя_кнопки() { // Нажата кнопка. $meta = $m->getMetadata(); ; ; ; } } ; ; ; ;
Цифровая подпись метаданных Пусть metadata – упакованные метаданные: –сервер хранит секретный ключ key –signed = metadata + "-" + md5(metadata + key) –в hidden-поле записывается signed –проверка: md5(left(signed) + key) == right(signed) Необходимо хранить key в секрете!
Защита от подделки форм Принудительная валидация: –hidden-поля должны быть константными: => $_POST['a'] = 'b' –выбранный элемент из single или multiple должен содержаться в списке: текст => $_POST['s'] = 'v' –форма послана именно тому скрипту, который указан в ее атрибуте action: => REQUEST_URI ~ "script" –DB constraints никто не отменял! Отмена принудительной валидации – => поле можно заполнять на JavaScript
Защита: "лишние" поля формы Провоцирование неявной зависимости от метаданных –Имеем форму: –Хакер добавляет "лишнее" поле: –Результат: изменение неожиданного поля MetaForm: неизвестные поля считаются подделкой
Неизбыточная валидация Привязка валидаторов В полю привязано имя валидатора: –вызов валидатора на стороне сервера (PHP) function validator_название($value, $metadata) –автопривязка валидатора на стороне клиента (JavaScript) validator_название = function(value, metadata) Привязка нескольких валидаторов Валидаторы должны быть ортогональными Передача параметров валидаторам Пароль: Еще раз:
Привязка сообщений об ошибках Ошибка валидации привязана к полю формы –Метаданные содержат ID (координаты) всех полей –Привязка ошибки к элементу на JavaScript ("модель светофора") –Фокус на ошибочном элементе Извлечение текста ошибки по имени валидатора (языковые константы) –'validator_ ' => 'Поле "%s" должно содержать корректный !' –Подстановка имен полей (sprintf)
Плюсы подхода MetaForm: –Родство с GUI-программированием –Неизбыточность –Прозрачность для любого framework-а –Легкость адаптации существующих проектов –Прозрачность для HTML-верстальщика Минусы: –Смешение логики метаданных и логики представления (характерно и для GUI)
Приходите к нам работать! МойКруг.ру теперь – сервис Яндекса Мы расширяем свою команду! Открыты вакансии для: –верстальщиков со знанием Smarty –отличных PHP-программистов –опытных БД-разработчиков (PostgreSQL, Oracle) –JavaScript-программистов Ждем Ваши резюме на