ASP.NET MVC: достаточно ли проверки аннотаций данных? - PullRequest
27 голосов
/ 13 октября 2009

Я широко использую проверку аннотации данных в ASP.NET MVC 2. Эта новая функция значительно сэкономила время, поскольку теперь я могу определять как проверку на стороне клиента, так и проверку на стороне сервера в одном месте. , Однако, проводя подробное тестирование, я понял, что кому-то довольно легко обойти проверку на стороне сервера, если бы я использовал только проверку аннотации данных. Например, если я определил обязательное поле, пометив свойство с помощью атрибута [Required] и поместил текстовое поле для этого обязательного поля в форме, пользователь мог бы просто удалить текстовое поле из DOM (что можно легко сделать с помощью Firebug) и теперь проверка аннотации данных не будет запускаться для этого свойства во время связывания модели внутри контроллера. Чтобы убедиться, что «требуемая» проверка запускается, я могу повторить проверку после того, как произойдет привязка ModelBinding, но тогда я повторю свою логику проверки.

Какова общая рекомендация по валидации? Достаточно ли валидации аннотации данных? Или же необходимо повторить проверку, чтобы убедиться, что проверки запускаются во всех ситуациях?

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

Я собираюсь опубликовать этот дополнительный комментарий как отдельный вопрос, поскольку он ставит вопрос, отличный от исходного.

Ответы [ 5 ]

18 голосов
/ 13 октября 2009

Я думаю, чтобы быть бдительным в отношении безопасности, вы должны сделать так, чтобы проверка сервера была приоритетом и чтобы это всегда было вашим запасным вариантом. Проверка вашего сервера должна работать без проверки клиента. Проверка клиента - это больше для UX, и это имеет первостепенное значение для вашего дизайна, это вторично по отношению к безопасности. Имея это в виду, вы обнаружите, что повторяете свою проверку. Часто целью является попытка спроектировать ваше приложение так, чтобы проверка сервера и клиента могла быть максимально интегрирована, чтобы уменьшить объем работы, необходимой для проверки на сервере и клиенте. Но будьте уверены, вы должны сделать оба.

Если при обходе проверки клиента (посредством манипулирования DOM) избегается проверка сервера (что, по-видимому, вы указываете), тогда проверка вашего сервера для этого экземпляра может быть использована неправильно. Вы должны снова вызывать проверку вашего сервера в действии контроллера или на уровне службы. Сценарий, который вы описываете, не должен побеждать проверку вашего сервера.

В сценарии, который вы описываете, метода атрибутов DataAnnotation должно быть достаточно. Похоже, вам просто нужно внести несколько изменений в код, чтобы убедиться, что проверка вашего сервера также запускается при отправке формы.

7 голосов
/ 13 октября 2009

Я связал xVal с DataAnnotations и написал свой собственный фильтр действий, который проверяет любые параметры типа сущностей в целях проверки. Поэтому, если какое-либо поле отсутствует в обратной передаче, этот валидатор заполнит словарь ModelState, следовательно, модель недействительна.

Требования:

  • все объекты моей сущности / модели реализуют интерфейс IObjectValidator, который объявляет метод Validate().
  • мой класс атрибутов называется ValidateBusinessObjectAttribute
  • Библиотека проверки xVal

Код фильтра действий:

public void OnActionExecuting(ActionExecutingContext filterContext)
{
    IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator);
    foreach (KeyValuePair<string, object> param in parameters)
    {
        object value;
        if ((value = param.Value) != null)
        {
            IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate();
            if (errors.Any())
            {
                new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key);
            }
        }
    }
}

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

[ValidateBusinessObject]
public ActionResult Register(User user, Company company, RegistrationData registrationData)
{
    if (!this.ModelState.IsValid)
    {
        return View();
    }
    ...
}
2 голосов
/ 04 ноября 2009

Я написал свой собственный ValidationService для MVC 1.0, скопировав шаблоны из DataAnnotationsRuleProvider от xVal и из DataAnnotationsModelBinder от Microsoft (и комментариев Мартийна). Интерфейс сервиса ниже:

public interface IValidationService
{
    void Validate(object instance);

    IEnumerable<ErrorInfo> GetErrors(object instance);
}

public abstract class BaseValidationService : IValidationService
{
    public void Validate(object instance)
    {
        var errors = GetErrors(instance);

        if (errors.Any())
            throw new RulesException(errors);
    }

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance);
}

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

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

Есть несколько других подводных камней, о которых вы должны знать:

  • Атрибут DataTypeAttribute по умолчанию в данных аннотации на самом деле не делают никаких проверка типа данных, так что вам нужно написать новый атрибут, который на самом деле использует xVal регулярный выражения (или что-то еще), чтобы выполнить тип данных на стороне сервера Проверка.
  • xVal не ходит свойства для создания на стороне клиента проверка, так что вы можете сделать некоторые изменения там, чтобы стать более надежным проверка на стороне клиента.

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

2 голосов
/ 13 октября 2009

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

Однако вы можете настроить модель DataAnnotation самостоятельно, чтобы убедиться, что свойства с [Обязательно] ДОЛЖНЫ быть опубликованы. (позже сообщу код позже).

UPDATE Получите источник связывания модели DataAnnotations и найдите эту строку в DataAnnotationsModelBinder.cs

// Only bind properties that are part of the request
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) {

Измените его на

// Only bind properties that are part of the request
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey);
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0;
if (contextHasKey || (!contextHasKey && isRequired)) {
1 голос
/ 07 декабря 2012

См. CodeProject Проверка входных данных на стороне сервера с использованием аннотаций данных

Проверка ввода может быть выполнена автоматически на стороне клиента в ASP.NET MVC или явная проверка модели на соответствие правилам. это Совет опишет, как это можно сделать вручную на стороне сервера Приложения ASP.NET или в коде репозитория WPF приложения.

        // Use the ValidationContext to validate the Product model against the product data annotations
        // before saving it to the database
        var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null);
        var validationResults = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true);
...