Два дня решаю эту проблему, но без особого успеха. Я использую asp.net webapi2 с jquery ajax на стороне клиента.
У меня есть поле редактирования для ввода текста заметки, допустимые символы - ^[©a-zA-Z0-9\u0900-\u097f,\.\s\-\'\"!?\(\)\[\]]+$ и два тега <LineBreak/> и <Link attr = "value"/> (может быть еще пара атрибутов в теге Link. Проблема в том, что НЕТ других тегов допустимы - это означает, что даже простой <br/> должен быть Эта отрицательная проверка оказывается немного сложной.
Запрос помощи в формулировании регулярного выражения для javascript на стороне клиента и проверки DataAnnotation на основе C# на стороне сервера.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


То, что вы пытаетесь сделать, - это очистить ввод пользователя, однако использование JavaScript и Regex - неправильный способ сделать это.
Не беспокойтесь о проверке пользовательского ввода во внешнем интерфейсе, по крайней мере, пока, в первую очередь нужно проверять его на стороне сервера, и лучший инструмент для работы - HtmlSanitizer. По их словам:
HtmlSanitizer is a .NET library for cleaning HTML fragments and documents from constructs that can lead to XSS attacks.
HtmlSanitizer can be customized at several levels:
- Configure allowed HTML tags through the property AllowedTags.
- Configure allowed HTML attributes through the property AllowedAttributes.
- Configure allowed CSS property names through the property AllowedCssProperties.
- Configure allowed CSS at-rules through the property AllowedAtRules.
- Configure allowed URI schemes through the property AllowedSchemes.
- Configure HTML attributes that contain URIs (such as "src", "href" etc.)
- Provide a base URI that will be used to resolve relative URIs against.
- Cancelable events are raised before a tag, attribute, or style is removed.
Я создал модель демонстрация на 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);
}
But would like to know why "regex is the wrong way to go about it".
Регулярное выражение не предназначено для этого типа задач, вам необходимо иметь возможность анализировать html-документ, то есть анализировать его теги, атрибуты и значения внутри этих атрибутов в древовидной структуре, чтобы иметь возможность правильно его дезинфицировать, потому что их слишком много крайние случаи, которые слишком сложно покрыть одним Regex. Regex лучше использовать для извлечения данных из источника, который уже находится в предсказуемой структуре, пользовательский ввод не является одной из этих вещей.
Несмотря на то, что ваш вариант использования достаточно прост, вы по-прежнему позволяете пользователям вводить HTML, который будет повторно отображаться для других пользователей в его необработанном формате, поэтому все, что вы пропустите, вызовет у вас головную боль в будущем.
Вот Шпаргалка по уклонению от фильтров XSS от OWASP, если бы Regex мог охватить все перечисленное здесь, я бы сказал, хорошо, но это настолько сложная задача для достижения этого в Regex, что это просто не имеет смысла.
HtmlSanitizer, с другой стороны, действительно охватывает проблемы, перечисленные в этой шпаргалке, он также активно поддерживается и специально создан для именно такого рода приложений, он также не является громоздким ни в коем случае, он может обрабатывать большие задачи по очистке со временем обработки в 50 Диапазон -100 мс.
Хотя идея использования библиотеки имеет некоторые преимущества, «вы по-прежнему позволяете пользователям вводить HTML, который будет повторно отображаться для других пользователей в исходном формате», не совсем верно по следующим причинам: 1. Разрешены только настраиваемые теги. LineBreak и Link, которые не являются «html» как таковые 2. Эти теги не будут отображаться другим пользователям в необработанном формате, поскольку для отображения этого содержимого будет использоваться преобразование xsl. Вот почему нам на самом деле не нужна «очистка HTML», а нужна только проверка пользовательских тегов.
Этого удалось добиться с помощью комбинации аннотации данных 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 на основе регулярных выражений.
Спасибо @Aydin Adn. Вчера я заглянул в эту библиотеку. Это казалось немного громоздким для простой проверки, поскольку нам действительно не нужно «дезинфицировать» весь ввод, если регулярного выражения достаточно. Но хотелось бы знать, почему «регулярное выражение - неправильный способ».