Потеря данных при передаче необработанного HTML из представления в контроллер в запросе POST - безопасность XSS и потеря информации

Преамбула

Мой вариант использования включает интерфейсный редактор WYSIWYG. Получение пользовательского ввода в формате HTML5/CSS из внешнего вида CSHTML. Получение ввода в действие Backend Controller через POST-запрос. И, наконец, занимаемся с ним причудливой базой данных.

Звучит довольно просто. Используя этот чудовищный редактор, он очень простой и настраиваемый.

Посмотреть

Редактор WYSIWYG textarea вложенный в form для отправки необработанных данных HTML редактора с помощью POST

    <form class="form" asp-controller="CreationController" asp-action="CreateSnowflakeBlogpost" method="post">
        <button type="submit" class="btn btn-link">Submit Snowflake Blogpost</button>
        <textarea name="snowflakeHtmlContent" id="joditEditor"> </textarea>
    </form>

Контроллер

Действие контроллера при получении параметра POST.

    [HttpPost]
    public async Task<IActionResult> CreateSnowflakeBlogpost(string snowflakeHtmlContent)
    {
        // store HTML content in DB and do fancy operations

        // redirect to something else
        return RedirectToAction("PreviewSnowflakeBlogpost");
    }

Проблема

Теги HTML5/CSS теряются при передаче данных POST. После проверки они успешно отправляются из просмотра. Однако параметр Action содержит неверные данные.

Похоже, здесь происходит дезинфекция, удаляя параметры POST из HTML-тегов, которые мы намеренно хотим сохранить.

Похоже, для этого есть возможные решения.

  • [Request.Unvalidated]аннотация. Не рекомендуется.
  • [AllowHtml]аннотация. Устарело. Смотрите здесь и здесь.
  • @Html.Raw(theString) здесь, но это для передачи небезопасных данных из контроллера в представление. Наш вариант использования противоположен.
  • В этом вопросе собраны предыдущие пункты. Все не работает.

Вопрос

Как передать необработанные данные HTML/CSS из представления в действие? удовлетворяющие следующим условиям:

  1. Без потери данных разметки.

  2. Предотвратить получение небезопасных данных, представляющих риск XSS. Согласно руководству.

1 ответ

Решение

Решение

В итоге я использовал Custom Model Binding, который обошел эту чрезмерно нетерпеливую очистку / потерю данных. В результате сохранились нужные мне HTML-теги.

Однако это создает риск XSS. Чтобы противодействовать передаче небезопасных данных, я использовал HtmlSanitizer, чтобы опустить небезопасные теги HTML/CSS.

Действие

Добавлено [ModelBinder(typeof(AllowSanitizedHtmlBinder))] аннотация к параметру

    [HttpPost]
    public async Task<IActionResult> CreateSnowflakeBlogpost([ModelBinder(typeof(AllowSanitizedHtmlBinder))] string snowflakeHtmlContent)
    {
        // store HTML content in DB and do fancy operations

        // redirect to something else
        return RedirectToAction("PreviewSnowflakeBlogpost");
    }

Подшивка пользовательской модели

Этот связыватель настраиваемой модели похож на реле и предотвращает потерю данных в нашем параметре POST. HtmlSanitizer здесь использовался перед привязкой значения для предотвращения XSS.

    // Custom Model Binding
    using Microsoft.AspNetCore.Mvc.ModelBinding;

    // HTML Sanitizer
    using Ganss.XSS;

    public class AllowSanitizedHtmlBinder: IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            var modelName = bindingContext.ModelName;

            // Try to fetch the value of the argument by name
            var valueProviderResult =
                bindingContext.ValueProvider.GetValue(modelName);

            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }

            bindingContext.ModelState.SetModelValue(modelName,
                valueProviderResult);

            var value = valueProviderResult.FirstValue;

            // Check if the argument value is null or empty
            if (string.IsNullOrEmpty(value))
            {
                return Task.CompletedTask;
            }

            // Sanitize HTML from harmful XSS markup
            var sanitizer = new HtmlSanitizer();
            var sanitizedValue = sanitizer.Sanitize(value);

            bindingContext.Result = ModelBindingResult.Success(sanitizedValue);

            return Task.CompletedTask;
        }
    }

[HELP] Отсутствующий элемент - понимание первопричины

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

Как видно здесь и здесь:

Вам больше не нужен [AllowHtml], потому что никто не отрицает HTML в ASP.NET Core 2.0.

Не нужен [AllowHtml] или RequestValidationEnabled, потому что в этой системе нет проверки запроса.

Любая помощь в демистификации первопричины будет ОЧЕНЬ признательна.

Источники

Мое решение было основано на:

  1. Это ответ. Хотяrequest.Unvalidated больше не поддерживается.
  2. Пользовательская привязка модели.
  3. HtmlSanitizer.
  4. Этот ответ помог мне указать правильное направление.
Другие вопросы по тегам