input type="text" name="lastname"

advertisement
Обработка метаданных и цифровое
подписывание HTML-форм
Дмитрий Котеров (dmitry@koterov.ru)
архитектор и главный разработчик MoiKrug.ru,
компания Яндекс
Что такое метаданные?
Фамилия: <input type="text" name="lastname" />
Пол:
<input type="radio" name="gender" value="m" /> Муж
<input type="radio" name="gender" value="f" /> Жен
• Данные
– то, что ввели
array(
"lastname" => "Пупкин",
"gender"
=> "m"
)
• Метаданные
–
"данные о структуре данных"
array(
"lastname" => array(
"type" => "text",
"caption" => "Фамилия",
"dbfield" => "p_lastname"
),
"gender" => array(
"type" => "single",
"dbfield" => "p_gender",
"elements" => array(
"m" => "Муж",
"f" => "Жен",
)
)
)
www.rit2007.ru
Типы полей с точки зрения
метаданных
• Текст
– <input type="text">, <input type="hidden">, <textarea>
• Файл (закачка)
– <input type="file">
• Единичный выбор
– <select></select>
– <input type="radio">…
• Множественный выбор (аналогично)
– <select multiple></select>
– <input type="checkbox">…
• Действие
– <input type="submit">, <input type="image">
www.rit2007.ru
Web- или GUI-приложение
•
Web-приложение
– "Размазанность"
– Двойная валидация (PHP, JS)
– Нет доверия метаданным
(неявная структура POST)
– Дублирование метаданных в
дизайне и обработчике
– Косвенный вызов обработчиков
Рисовальщик
формы
errors
Обработчик
формы
•
GUI-приложение
– Централизованная обработка
– Непосредственная валидация
– "Доверие" метаданным (все в
рамках одной оконной формы)
– Форма "рисуется" и
обрабатывается в едином месте
– Мгновенные обработчики кнопок
HTML
Пользова
тель
POST
GUI-приложение:
форма + обработчики
событий
Пользователь
www.rit2007.ru
"Размазанность": неявные
зависимости от метаданных
• Различные
компоненты
системы
– Структура БД
– HTML-представление
формы
– Рисовальщик (код
начального заполнения
формы)
– Обработчик (код приема
данных и записи в БД)
– Серверный валидатор
(PHP)
– Клиентский валидатор
(JS)
• Как их объединяют,
чтобы обойти
проблему
– Структура БД
– HTML-представление
формы + клиентский
валидатор
– Рисовальщик +
обработчик + серверный
валидатор
www.rit2007.ru
Централизация метаданных
• Репозиторий метаданных
Metadata
• Подход MetaForm – похож
на GUI-формы
HTML
+
Metadata
HTML
+ JS
БД
Рисовальщик
+ обработчик
+ валидатор
БД
• Генератор по явно
выделенным метаданным
Рисовальщик
+ модификатор
+ обработчик
+ валидатор
• сложность доработки
• неуниверсальность
www.rit2007.ru
MetaForm: шаблон + метаданные
<label for="l">Фамилия</label>:
<input type="text"
name="lastname"
id="l"
meta:dbfield="p_lastname"
meta:validator="filled"
/>
Пол:
<label for="m">Муж</label>
<input type="radio"
name="gender"
value="m"
id="m"
meta:dbfield="p_gender" />
<label for="f">Жен</label>
<input type="radio"
name="gender"
value="f"
id="f"/>
•
•
Метаданные объединены с
представлением (как в GUI)
Автоматическое извлечение
метаданных
Использование возможностей
HTML для привязки заглавия
Назначение валидаторов
(серверных + клиентских)
Назначение произвольных метаатрибутов
Отправка формы "на себя"
•
Обработка HTML "на лету":
•
•
•
•
– Легкость адаптации старых
проектов
– Совместимость с любыми
имеющимися framework-ами
– Неизбыточность ("а добавим-ка
новое поле")
www.rit2007.ru
MetaForm: традиционная обработка
•
•
•
Обработка формы:
– распаковка метаданных
– проверка цифровой подписи
– валидация
– сохранение сообщений об
ошибках
– сохранение сообщений в сессии
– "редирект на себя"
Подготовка метаданных
– извлечение метаданных из HTML
формы, "чистка" формы
– упаковка и цифровое
подписывание метаданных
– вставка метаданных в hiddenполе
Отрисовка формы:
– вставка данных из $_POST
(FormPersister)
– назначение клиентских
валидаторов
– привязка сообщений об ошибках к
полям
switch ($m->process()) {
// Простой показ формы.
case "INIT":
$_POST = <достать из БД>;
break;
// Нажата кнопка.
case "имя_кнопки":
$meta = $m->getMetadata();
<записать в БД>;
<запомнить сообщ. успеха>;
<редирект на себя>;
break;
}
// Произошла ошибка валидации
<показать ошибки и сообщения>;
<заполнить поля из $_POST>;
<подготовить метаданные>;
<отрисовать форму>;
www.rit2007.ru
MetaForm: событийная обработка
// Контроллер Page
class Page {
function init() {
// Простой показ формы.
$_POST = <достать из БД>;
}
}
function имя_кнопки() {
// Нажата кнопка.
$meta = $m->getMetadata();
<записать в БД>;
<запомнить сообщ. успеха>;
<редирект на себя>;
}
• switch-case хорошо
подходит при переводе
старой системы на
MetaForm
• событийная модель
удобна для построения
CMF
<!-- Шаблон Page -->
<показать ошибки и сообщения>;
<заполнить поля из $_POST>;
<подготовить метаданные>;
<показать форму>;
www.rit2007.ru
Цифровая подпись метаданных
• Пусть metadata – упакованные метаданные:
–
–
–
–
сервер хранит секретный ключ key
signed = metadata + "-" + md5(metadata + key)
в hidden-поле записывается signed
проверка: md5(left(signed) + key) == right(signed)
• Необходимо хранить key в секрете!
www.rit2007.ru
Защита от подделки форм
• Принудительная валидация:
– hidden-поля должны быть константными:
<input type="hidden" name="a" value="b">
=> $_POST['a'] = 'b'
– выбранный элемент из single или multiple должен содержаться в
списке:
<select name="s"><option value="v">текст</select>
=> $_POST['s'] = 'v'
– форма послана именно тому скрипту, который указан в ее атрибуте
action:
<form action="script">
=> REQUEST_URI ~ "script"
– DB constraints никто не отменял!
• Отмена принудительной валидации
– <input type="hidden" meta:dynamic>
=> поле можно заполнять на JavaScript
www.rit2007.ru
Защита: "лишние" поля формы
• Провоцирование неявной зависимости от метаданных
– Имеем форму:
<input type="text" name="person[firstname]" />
<input type="text" name="person[lastname]" />
– Хакер добавляет "лишнее" поле:
<input type="text" name="person[firstname]" />
<input type="text" name="person[lastname]" />
<input type="hidden" name="person[is_admin]" value="1" />
– Результат: изменение неожиданного поля
• MetaForm: неизвестные поля считаются подделкой
www.rit2007.ru
Неизбыточная валидация
• Привязка валидаторов
<input meta:validator="filled email">
• В полю привязано имя валидатора:
– вызов валидатора на стороне сервера (PHP)
function validator_название($value, $metadata)
– автопривязка валидатора на стороне клиента (JavaScript)
validator_название = function(value, metadata)
• Привязка нескольких валидаторов
<input meta:validator="filled email">
• Валидаторы должны быть ортогональными
• Передача параметров валидаторам
Пароль: <input type="password"
name="pass"
meta:validator="password_match"
meta:match_field="confirm"
/>
Еще раз: <input type="password" name="confirm" />
www.rit2007.ru
Привязка сообщений об ошибках
• Ошибка валидации привязана к полю формы
– Метаданные содержат ID (координаты) всех полей
– Привязка ошибки к элементу на JavaScript ("модель
светофора")
– Фокус на ошибочном элементе
• Извлечение текста ошибки по имени валидатора
(языковые константы)
– 'validator_email' => 'Поле "%s" должно содержать
корректный E-mail!'
– Подстановка имен полей (sprintf)
www.rit2007.ru
Резюме
• Плюсы подхода MetaForm:
–
–
–
–
–
Родство с GUI-программированием
Неизбыточность
Прозрачность для любого framework-а
Легкость адаптации существующих проектов
Прозрачность для HTML-верстальщика
• Минусы:
– Смешение логики метаданных и логики
представления (характерно и для GUI)
www.rit2007.ru
Приходите к нам работать!
• МойКруг.ру теперь – сервис Яндекса
• Мы расширяем свою команду!
• Открыты вакансии для:
–
–
–
–
верстальщиков со знанием Smarty
отличных PHP-программистов
опытных БД-разработчиков (PostgreSQL, Oracle)
JavaScript-программистов
Ждем Ваши резюме на
http://moikrug.ru/hire/
www.rit2007.ru
Download