带有少量特殊标签的备忘录字段(客户端和服务器端)的正则表达式验证
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