1

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

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

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

4

2 回答 2

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。
  • 在移除标签、属性或样式之前引发可取消事件。

我使用该库在 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);
}

编辑

但想知道为什么“正则表达式是错误的方法”。

正则表达式不适用于此类任务,您需要能够解析 html 文档,这意味着在树状结构中的这些属性中解析其标签、属性和值,以便能够正确清理它,因为太多了仅使用正则表达式难以涵盖的边缘情况。正则表达式更适合用于从已经存在于可预测结构中的源中抓取数据,用户输入不是其中之一。

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

这是来自 OWASP 的XSS 过滤器规避备忘单,如果 Regex 可以涵盖此处列出的所有内容,我会说很好,但在 Regex 中实现这一点是一项艰巨的任务,它只是没有意义。

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

于 2018-09-29T04:16:49.437 回答
0

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

[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 验证在客户端应用了相同的解决方案。

于 2018-09-30T14:06:23.947 回答