Проверка регулярного выражения для поля memo (на стороне клиента и сервера) с несколькими специальными тегами

Обдумывал эту проблему два дня без особой удачи. Я использую asp.net webapi2 с jquery ajax на стороне клиента.

У меня есть поле редактирования для ввода текста заметки, допустимые символы: ^[©a-zA-Z0-9\u0900-\u097f,\.\s\-\'\"!?\(\)\[\]]+$ и два тега <LineBreak/> и <Link attr="value"/> (может быть еще пара атрибутов в теге Link. Проблема в том, что никакие другие теги не разрешены - это означает, что даже простой <br/> должен быть Предотвращено Эта отрицательная проверка оказывается немного сложной.

Запрос помощи в формулировании регулярного выражения для javascript на стороне клиента и проверке DataAnnotation на основе C # на стороне сервера.


person Rohit Sahasrabudhe    schedule 29.09.2018    source источник


Ответы (2)


То, что вы пытаетесь сделать, это дезинфицировать пользовательский ввод, однако использование JavaScript и Regex - неправильный способ сделать это.

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

HtmlSanitizer — это .NET-библиотека для очистки фрагментов HTML и документов от конструкций, которые могут привести к XSS-атакам.

HtmlSanitizer можно настроить на нескольких уровнях:

  • Настройте разрешенные теги HTML с помощью свойства AllowedTags.
  • Настройте разрешенные атрибуты HTML с помощью свойства AllowedAttributes.
  • Настройте разрешенные имена свойств CSS с помощью свойства AllowedCssProperties.
  • Настройте разрешенные at-правила CSS с помощью свойства AllowedAtRules.
  • Настройте разрешенные схемы URI с помощью свойства AllowedSchemes.
  • Настройте атрибуты HTML, содержащие URI (например, «src», «href» и т. д.)
  • Укажите базовый URI, который будет использоваться для разрешения относительных URI.
  • Отменяемые события возникают перед удалением тега, атрибута или стиля.

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

void Main()
{
    var allowedTags = new[]{"LineBreak", "Link"};
    var allowedAttributes = new[]{"attr"};
    var sanitizer = new HtmlSanitizer(allowedTags: allowedTags, allowedAttributes: allowedAttributes);
    //sanitizer.
    var html = @"<script>alert('xss')</script><div onload=""alert('xss')""" + @"style=""background-color: test"">Test<img src=""test.gif""" + @"style=""background-image: url(javascript:alert('xss')); margin: 10px""></div>
    <LineBreak></LineBreak>

    <Link attr=""v123""/>";
    var sanitized = sanitizer.Sanitize(html);
    Console.WriteLine(sanitized);
}

Редактировать

Но хотел бы знать, почему «регулярное выражение - неправильный способ сделать это».

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

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

Вот Шпаргалка по уклонению от фильтра XSS от OWASP, если Regex сможет охватить все, что здесь перечислено, Я бы сказал, хорошо, но добиться этого в Regex настолько сложно, что это просто не имеет смысла.

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

person Aydin    schedule 29.09.2018
comment
Спасибо @Aydin Adn. Вчера заглянул в эту библиотеку. Это казалось немного громоздким для простой проверки, поскольку нам действительно не нужно «санировать» весь ввод, если достаточно регулярного выражения. Но хотелось бы знать, почему регулярное выражение - неправильный способ сделать это. - person Rohit Sahasrabudhe; 29.09.2018
comment
Хотя использование библиотеки имеет некоторые преимущества, вы по-прежнему позволяете пользователям вводить HTML-код, который будет повторно отображаться другим пользователям в необработанном формате, что не совсем верно по следующим причинам: 1. Разрешены только пользовательские теги: LineBreak и Ссылка, которая не является html как таковой 2. Эти теги не будут отображаться для других пользователей в необработанном формате, поскольку для отображения этого контента будет использоваться преобразование xsl. Вот почему нам на самом деле не нужна очистка html, а просто проверка пользовательских тегов. - person Rohit Sahasrabudhe; 29.09.2018

Этого удалось достичь с помощью комбинации аннотации данных RegularExpression, которая позволяет использовать угловые скобки (таким образом, настраиваемые теги).

[RegularExpression(@"([©a-zA-Z0-9\u0900-\u097f,\.\s\-\'\""!?\(\)\[\]\<\>\/]*)")]

и класс ValidationAttribute, который проверяет наличие нежелательных тегов (кроме LineBreak и Link)

public class CustomTagValidatorAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        Regex re = new Regex(@"(<(?!(LineBreak\s*|Link\s+[\s\w\'\""\=]*)\/?>))", RegexOptions.Multiline);
        return re.Match(value.ToString()).Length == 0 ? ValidationResult.Success : new ValidationResult(Resources.ErrorStrings.InvalidValuesInRequest);
    }
}

Оба атрибута применяются к свойству класса, как показано ниже:

[CustomTagValidator]
[RegularExpression(@"([©a-zA-Z0-9\u0900-\u097f,\.\s\-\'\""!?\(\)\[\]\<\>\/]*)")]
public string PropertyToValidate { get; set; }

Также добавлен ActionFilterAttribute, чтобы обеспечить выполнение проверки перед вызовом действия контроллера —

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid == false)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

и применил это к соответствующему действию контроллера, как показано ниже:

    [ValidateModel]
    public HttpResponseMessage Post([FromBody] MyModel mm)

Надеюсь, это поможет кому-то, кто столкнулся с подобными проблемами.

Чуть не забыл, такое же решение было применено на стороне клиента с использованием той же проверки javascript на основе регулярных выражений.

person Rohit Sahasrabudhe    schedule 30.09.2018