带有少量特殊标签的备忘录字段(客户端和服务器端)的正则表达式验证

Posted

技术标签:

【中文标题】带有少量特殊标签的备忘录字段(客户端和服务器端)的正则表达式验证【英文标题】:Regex validation for memo field (client and server side) with few special tags 【发布时间】:2019-03-05 00:19:49 【问题描述】:

已经解决这个问题两天了,没有任何真正的运气。我在客户端使用带有 jquery ajax 的 asp.net webapi2。

我有一个用于输入备注文本的编辑框,允许的字符是 ^[©a-zA-Z0-9\u0900-\u097f,\.\s\-\'\"!?\(\)\[\]]+$ 和两个标签 <LineBreak/><Link attr="value"/>(可能是链接标签中的更多属性。问题是不允许其他标签 -这意味着即使是简单的<br/> 也应该被阻止。事实证明,这种否定检查有点复杂。

请求帮助在客户端为 javascript 制定正则表达式并在服务器端为基于 c# 的 DataAnnotation 检查。

【问题讨论】:

【参考方案1】:

您尝试做的是清理用户输入,但是,使用 JavaScript 和 Regex 是错误的方法。

不要担心在前端验证用户输入,至少现在还没有,重点应该首先在服务器端验证它,最好的工具是htmlSanitizer。用他们的话说:

HtmlSanitizer 是一个 .NET 库,用于从可能导致 XSS 攻击的构造中清除 HTML 片段和文档。

可以在多个级别自定义 HtmlSanitizer:

通过属性 AllowedTags 配置允许的 HTML 标记。 通过属性 AllowedAttributes 配置允许的 HTML 属性。 通过属性 AllowedCssProperties 配置允许的 CSS 属性名称。 通过属性 AllowedAtRules 配置允许的 CSS at-rules。 通过属性 AllowedSchemes 配置允许的 URI 方案。 配置包含 URI 的 HTML 属性(例如“src”、“href”等) 提供将用于解析相对 URI 的基本 URI。 在标签、属性或样式被移除之前引发可取消事件。

我使用该库模拟了一个 demo on 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 文档,这意味着在树状结构中解析其标签、属性和这些属性中的值,以便能够正确清理它,因为有太多的边缘情况很难用正则表达式来覆盖。正则表达式更适合用于从已经存在于可预测结构中的源中抓取数据,用户输入不是其中之一。

即使您的用例足够简单,您仍然可以让用户输入 HTML,这些 HTML 将以原始格式重新显示给其他用户,因此您错过的任何内容都会让您头疼。

这是来自 OWASP 的 XSS Filter Evasion Cheat Sheet,如果 Regex 可以涵盖此处列出的所有内容,我会说很好,但在 Regex 中实现这一目标是一项艰巨的任务,它只是没有意义。

另一方面,HtmlSanitizer 确实涵盖了该备忘单上列出的问题,它也得到积极维护,专门为这类应用程序构建,它也不笨重,它可以处理大型清理任务,处理时间在 50-100ms 范围内。

【讨论】:

感谢@Aydin Adn。我昨天看了这个图书馆。简单的验证似乎有点笨重,因为如果正则表达式足够,我们真的不需要“清理”所有输入。但想知道为什么“正则表达式是错误的处理方式”。 虽然关于使用库的观点有一些好处,但“您仍然允许用户输入 HTML,这些 HTML 将以原始格式重新显示给其他用户”由于以下原因并不完全正确- 1. 仅允许自定义标签是 LineBreak 和 Link,它们不是“html” 2. 这些标签不会以原始格式显示给其他用户,因为 xsl 转换将用于显示该内容。这就是为什么我们实际上不需要“html sanitation”而只需要验证自定义标签。【参考方案2】:

通过结合允许尖括号(因此自定义标签)的正则表达式数据注释来实现这一点

[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 验证。

【讨论】:

以上是关于带有少量特殊标签的备忘录字段(客户端和服务器端)的正则表达式验证的主要内容,如果未能解决你的问题,请参考以下文章

C# socket服务器端 多线程客户端 如何少量使用CPU

Mongoose .find 带有 req.params 数组?和 res.json 每个值和计数的数组?

go 客户端的请求带有请求头和cookie值得请求

服务器端和客户端方法

如果使用标签,浏览器会拒绝非数字输入吗?

是否有带有标签和文本字段的可重用 UITableViewCell?