Опасности в автоматической привязке модели в ASP.NET MVC
В своем посте про безопасность сайтов в ASP.NET MVC я совершенно забыл про одну очень неприятную атаку, применимую к действиям контроллеров, использующим автоматическую привязку модели и UpdateModel/TryUpdateModel. Представьте себе ситуацию, что на сайте добавляются комментарии, которые обязательно должны проходить модерацию, поэтому у них есть свойство IsApproved, по умолчанию в базе данных заданное как false. Например, модель выглядит как:
Представим себе, что при отправке формы пользователь заполняет поле textarea с идентификатором Text и input поле с идентификатором Author, а на стороне сервера действие, сохраняющее комментарий в базу данных выглядит как:
В этом случае нехороший пользователь может эмулировать POST обращение на сервер и передать пару значений IsApproved = true, чтобы автоматически показать сообщение без модерации. В этом сценарии, может быть, это не так страшно – комментарий можно удалить, однако похожий сценарий может быть применим к каким-то более важным бизнес-данным, поэтому такого допускать нельзя. Есть три основных подхода, позволяющие избежать подобной проблемы. Минимум кода – привязывать только нужные поля Для этого можно передавать параметры в метод UpdateModel():
Еще один вариант, пометить аргумент действия атрибутом Bind:
Атрибут Bind можно использовать и в варианте [Bind(Exclude = “”)], указывая список полей, привязку которых не следует осуществлять. Однако метод с указанием только нужных полей оказывается надежнее при дальнейших модификациях модели – свойства остаются защищены от изменений, несмотря на то, что добавляются новые свойства в модели. Чуть больше кода – использовать промежуточные модели. Такой подход подразумевает создание отдельных классов моделей для использования на стороне представлений, часто называемых ViewModel. Эти модели являются упрощенными вариантами полноценных моделей данных и предоставляют только свойства, которые необходимы обработки получаемых данных. Например, для комментариев такая модель может выглядеть так:
В этом случае при обновлении базы данных придется конструировать новые объекты Comment, присваивать значения полей объектов типа CommentViewModel объектам типа Comment и сохранять уже объекты Comment в базу данных. Совсем много кода – привязывать поля вручную Самый гибкий, но и самый кропотливый в реализации способ – отказаться от использования методов UpdateModel и TryUpdateModel и проводить валидацию всех полей и конструирование нужных объектов самостоятельно. Этот метод оправдан когда для передаваемых данных необходимо выполнять сложные проверки и конструировать не один объект, а набор объектов со сложной логикой связи между ними. Кроме того, этот метод любят те, кто боится доверять привязку данных MVC Framework. |