.NET

индекс
121,03

Изменения в валидации финальной версии ASP.NET MVC 2

и несколько вопросов безопасности, на которые стоит обратить внимание

imageБрэд Уилсон (Brad Wilson), один из разработчиков в группе ASP.NET MVC, сообщил в своем блоге о грядущих концептуальных изменениях, которые будут произведены в финальной версии ASP.NET MVC 2.

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

Для демонстрации я хотел бы определить простую модель данных. Ради примера я выбрал упрощенную модель одной записи digg-подобного сервиса. В таких сервисах каждая запись – это текст ссылки на полезный ресурс в сети, плюс описание этой ссылки.
В статье я использую изображения для демонстрации кода. Это связано с тем, что статью я планирую размещать на нескольких ресурсах и тратить время на раскрашивание синтаксиса в каждом из них мне не хочется. Взамен, в конце статьи я прилагаю исходные коды в виде готового проекта.
Итак, класс Story.cs:

image

Здесь, кроме полей Url и Description, объявлены поля Id (идентификатор), Approved (флаг указывающий на то, что запись прошла модерацию) и CreateDate (дата создания записи). Атрибут Bind в данном случае указывает на то, что при связывании данных с экземпляром модели не нужно связывать значения Id.

Для демонстрации нам понадобится форма для ввода и поле для вывода результатов. Создадим следующую разметку:

image

Попробуем что-нибудь ввести и посмотрим на результат:

image

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

image

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

image

Пока все выглядит хорошо и красиво. Однако представьте себе такой вариант: поле для ввода описания не было добавлено в одном из вариантов формы при создании другой страницы другим разработчиком. Или, что более трагично, злоумышленник формирует и отправляет данные вообще без указания поля “Описание”. Как в этом случае поведет себя наше приложение?

Для демонстрации такой попытки отправить плохие данные я сформировал простой запрос, который содержит значение Url, но не значение Description. Результат запроса вы можете посмотреть ниже:

image

Как вы видите, Description равен null, однако модель данных считается валидной. В случае, если нет дополнительных проверок, этот запрос привел бы записи невалидной (согласно наших представлений) модели в базу данных.

Проблема


В чем же подвох? Дело в том, что валидация, которая работает в ASP.NET MVC 2 всех публично существующих на данный момент версий (последняя версия — RC) в своей работе отталкивается от значений формы. Иными словами, валидации подлежат только те поля, которые были переданы на сервер, остальные поля валидацию не проходят.

Проблема данного момента стоит в следующем: является или нет серверная валидация механизмом защиты от несанкционированного доступа или нет? До недавнего момента ответом по сути было – нет. Валидация являлась средством проверки пользовательского ввода на определенные условия.

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

Решение


Что же предлагается в замен? Выход состоит в том, чтобы изменить поведение валидации с зависимости от формы к зависимости от модели. То есть привести поведение к тому, что ожидается большинством разработчиков. В финальной версии ASP.NET MVC 2 именно это и будет сделано: валидация перестанет зависеть от переданных значений, но будет полностью зависеть от модели данных.

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

Детали или “не все так просто”


Есть несколько моментов в предстоящих нововведениях на которые необходимо обратить внимание.

Комплексные типы


Правила валидации вложенных комплексных объектов внутри модели будут влиять на валидацию только в том случае, когда на форме есть хотя бы одно поле из этого комплексного типа. Например, если в классе Person объявлено свойство типа Address, то правила валидации для Address будут применяться только если в запросе на сервер будет участвовать хотя бы одно из свойств Address.

Изменения в обработке атрибута Bind


В связи с изменениями механизма валидации, обработка атрибута Bind, который установлен для модели изменена. В финальной версии MVC 2 валидация будет производится для всех свойств модели, независимо от того, помещены ли свойства в список Excluded атрибута Bind или нет.

Ранее, задав в списке Excluded определенные поля можно было добиться частичной валидации модели. Отныне, это невозможно – проверяться на правила валидации будут все свойства.

Required для non-nullable типов


В связи с тем, что валидация будет отталкиваться от модели, то использование Required для non-nullable типов бесполезно. Невозможно определить было или не было передано значение из формы, так как value-тип имеет значение по-умолчанию.

Параметры как часть модели


Другая возможная проблема состоит в том, что разработчик может использовать в качестве параметров действия не строгую модель представления, но часть ее:

image

Здесь, редактирование записи осуществляется первоначальным связыванием одного параметра id. Затем из репозитория загружается существующая запись и производится попытка ее обновления. Проблема возникает тогда, когда данные отправленные на сервер не содержат всех необходимых значений. Например, то же самое поле “Описание” не заполнено. В представленном примере, валидация для поля Description не сработает ни в одном из мест выполнения кода и модель будет неверно сохранена.

Решением проблемы будет использование строго типа модели, вместо части ее. Тогда валидация сработает на этапе связывания параметров действия.

Передача лишних параметров


Еще одна проблема, которая может возникнуть при использовании валидации – это возможность для злоумышленника отправить значения таких полей модели, которые не должны быть отправлены на сервер. Это может быть значение Approved для нашей модели Story. Значение Approved для записи означает, что запись прошла модерацию, то есть это значение определяет параметр безопасности системы и доступ к нему должен быть явно ограничен.

Я отправил с нашей формы зловредный запрос, посмотрите на результат:

image

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

Чтобы избежать подобной ситуации необходимо внимательно относиться к механизму валидации и правильно планировать ваши модели. Например, для того, чтобы избежать подобного взлома премодерации необходимо в модели для атрибута Binв добавить в список Excluded значение Approved:

image

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

Заключение


В этой статье я рассмотрел нововведения для механизма валидации, которые будут произведены в финальной версии ASP.NET MVC 2. Кроме того, были затронуты вопросы безопасности при использовании связывания данных, валидации и отправки данных с формы.

Автоматическая валидация и связывание данных – это крайне полезные механизмы, которые могут значительно облегчить вашу жизнь. Но их использование налагает обязанности по соблюдению определенных правил безопасности, про которые не нужно забывать. Надеюсь, эта статья поможет вам строить безопасные сайты на ASP.NET MVC. Приятной разработки, коллеги!
Приложение: исходные коды из статьи

Progg it
_________
Текст подготовлен в ХабраРедакторе
+8
26 января 2010, 11:02
14

комментарии (9)

0
Kefir #
По-моему, они просто взяли S#arp Architecture и потихоньку переносят все его фишки в MVC 2, не забывая грамотно пиарить.
По мне так единственное стоящее нововведение MVC 2 это строго типизированные html-помогалки
0
woworks #
Спасибо за статью.
Пользуясь случаем хочу спросить… работаю в VS2008 SP1 — ASP.NET MVC 1.0 — студия довольно часто вылетает… замечено, что часто при copy-paste операциях — не было у кого такой же проблемы?
0
Igorbek #
Очень хорошо, что всё-таки будет валидация именно модели. Я был очень огорчен, когда узнал, что валидация раньше была устроена по-другому.

Все-таки хочу сказать, что возможности связывания параметров в MVC довольно примитивны. В частности, модель связки плоская — не учитываются зависимости между параметрами. Например, на форме приема оплаты, я хочу иметь выбор между методами оплаты и соответственно специфические для каждого метода параметры. Такая модель свяжет и проверит все параметры, хотя на самом деле необходимо связать только часть параметров и, соответственно только часть параметров проверять.
Также что плохо, нет никакого механизма расширения или переопределения связывания. Могли бы сделать какой-нибудь BindContext, который бы содержал информацию о связывании, и это бы, кстати могло бы решить проблему с проверкой не-nullable типов (так как валидатор смог бы проверить сам факт передачи параметра).
0
Igorbek #
Эх, наврал, извините! Сейчас покопался — есть какие-то возможности по изменению связывания.
Есть IModelBinder, который можно реализовать самому и заменить стандартный. Надо лучше разобраться.
–1
XaocCPS #
да, связывание в MVC можно полностью переопределить, даже в версии 1.0
0
Ababagalamaga #
Меня немного смущает Exclude для Approved свойства — ведь в админке этот биндинг может понадобится. Как быть? Делать связывание полей, пришедших в запросе с ViewModel? А валидация будет уже в модели.
0
Igorbek #
Согласен. Вот мне тоже не нравится, что связыванием управляем для всего класса, и нельзя управлять выборочно в разных ситуациях. Может быть можно указать BindAttribute у параметра action'а?
–1
XaocCPS #
можно управлять, просто изучить больше все возможности механизма связывания
–1
XaocCPS #
в админке надо использовать два параметра: модель и bool approved, модель безопасно забиндится и во второй параметр попадет то что вам надо

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