12

我有一个控制器可以接受

public class MyModel
{
   [MaxLength(400)]
   public string Message { get; set; }
}

我有一个 WebApi 发布操作

public HttpResponseMessage Post(MyModel viewModel)
{
            if (!ModelState.IsValid)
                return new HttpResponseMessage(HttpStatusCode.BadRequest);                 
            ...
}

并采取行动。

由于内容是由 javascript 写出的,而不是直接在视图中写出确切的内容,因此也没有关于危险内容的 asp.net 警告。

我想防止 XSS。目前我正在做

HttpUtility.HtmlEncode(Regex.Replace(p.Message, @"<[^>]*>", String.Empty))

在获取操作中。(从Using C# regular expressions to remove HTML tags 中获取一些代码)

我应该使用的 Asp.Net 中是否有任何内置保护?有什么属性可以用来装饰我的模型吗?

我注意到这个http://stephenwalther.com/archive/2012/06/25/announcing-the-june-2012-release-of-the-ajax-control-toolkit.aspx但点击http://wpl。 codeplex.com/似乎受到了非常糟糕的审查。

4

5 回答 5

12

就您现在的代码而言,用户可以只注入不使用脚本标记的 JavaScript。

有一个可以使用的 XSS 漏洞的常见列表。

现在你接受一个“字符串”,你解析出来的只是 HTML 标签。不幸的是,有很多不依赖 HTML 的 XSS 攻击。

例如,将以下内容添加到 Firefox 中的 GET 请求中:%22onmouseover=prompt%28%29//将允许该人注入 JavaScript。

最好的办法是使用Microsoft 的 AntiXss 库,并专门对 GET 和 POST 请求的参数进行编码。

(我必须去上班,但稍后我会发布更多代码来说明如何做到这一点)。

于 2012-09-27T12:36:46.983 回答
11

注意:请阅读整个答案,我从 AntiXss 库切换到 HtmlSanitizer。还测试测试测试!我不是安全专家。

根据官方文档,您可以在您的中执行以下操作web.config

<httpRuntime encoderType="System.Web.Security.AntiXss.AntiXssEncoder" /> 

您不再需要安装 AntiXss 库,因为它现在包含在 .NET 4.5 中。

更新:

事实证明,在 web.config 中设置 encoderType 是不够的,我最终做的是拦截反序列化的 json 并像这样验证它:

public class AntiXssConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var stringValue = (string) reader.Value;
        ThrowIfForbiddenInput(stringValue);
        return stringValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var token = JToken.FromObject(value);
        token.WriteTo(writer);
    }

    private static void ThrowIfForbiddenInput(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return;
        }

        var encoded = AntiXssEncoder.HtmlEncode(value, true);
        if (value != encoded)
        {
            throw new Exception("Forbidden input. The following characters are not allowed: &, <, >, \", '");
        }
    }
}

像这样使用转换器:

config.Formatters.JsonFormatter.SerializerSettings.Converters = new List<JsonConverter>
{
    new AntiXssConverter()
};

如果数据包含任何非法字符,我只是抛出一个异常,因为我不想在我的后端接受它。其他人可能只想简单地清理输入。

为了以防万一,另一件事是配置 WebAPI 以转义 HTML 输出,如下所示:

config.Formatters.JsonFormatter.SerializerSettings.StringEscapeHandling = 
    StringEscapeHandling.EscapeHtml;

这涵盖了我的一切。

第二次更新:

我决定从使用 AntiXss 库更改为使用HtmlSanitizer,因为 AntiXss 对所有外来字符(ä、ö 等)进行编码过于严格,即使 unicode 块我也无法允许它们在白名单中。

这个库的另一个好处是它使用 OWASP XSS Filter Evasion Cheat Sheet 进行了单元测试。点击这里了解更多信息

第三次更新:

如果您决定使用上面的 JsonConverter 方式,则可以通过简单地在客户端设置不同的 Content-Type(例如“application/x-www-form-urlencoded”)来绕过它,并且请求将通过服务器。

为了避免这种情况,我清除了所有其他格式化程序,只留下 JSON 一个,如下所示:

config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());

然后,为了忽略特定属性(例如密码字段)上的 XSS 转换器,我从以下答案中找到了一个很好的解决方案,即创建一个虚拟的“NoConverter”类,该类默认使用特定的默认转换器特性:

public class NoConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanRead => false;
    public override bool CanWrite => false;
}

用法:

[JsonConverter(typeof(NoConverter))]
public string NewPassword { get; set; }

我可能仍然错过了一些东西,我绝不是专业的网络开发人员,但这是一次有趣的旅程...... :-)

于 2019-03-16T18:50:50.617 回答
7

有两种主要的思想流派可以防止 XSS 攻击。

  • 输出编码
  • 输入验证

对于输出编码, Server.HtmlEncode(p.message) 应该可以解决问题(因此您当前在示例中的内容将起作用,如果您不想这样做,则不需要进行正则表达式替换。输出编码将阻止XSS)。在这里,我假设您想要进行 HTML 编码而不是 Url 编码等。

看起来您正在使用 .NET MVC 框架。您可以使用DataAnnotations来执行白名单验证(仅允许安全字符)与黑名单。我会考虑使用RegularExpressionAttribute。例如:

public class MyModel
{
   [RegularExpression(@"^[a-zA-Z''-'\s]{1,400}$", ErrorMessage = "Characters are not allowed.")]
   public string Message { get; set; }
}

希望这可以帮助。

于 2012-10-03T03:04:19.190 回答
1

用于在使用 WebAPI 时停止 XSS。最好使用中间件来避免/停止 XSS。我找到了一个最好的链接/博客,请更喜欢下面的链接来添加中间件。

https://www.loginradius.com/blog/async/anti-xss-middleware-asp-core/

在这个链接中,所有步骤都包括在内,请完成并实施。

将中间件添加到 Startup.cs 类中只有一个问题。

app.UseAntiXssMiddleware();

而不是我使用下面的语法在 Startup.cs 类中添加中间件。

app.UseMiddleware<AntiXssMiddleware>();
于 2021-07-06T15:20:56.300 回答
-3

为了防止 Web 的安全缺陷:

尝试减轻伤害。使用防伪令牌,确保您只接受某些操作的 ssl。确保 cookie 得到适当保护。总体而言,最小化攻击面并设置障碍使其更难。

为了防止用户输入:

参数化用户输入,如果不能参数化,编码,但是编码要非常小心,很多漏洞都是由于编码不当造成的。编码还取决于输入的使用位置和方式。约束和验证用户输入,确保服务器只接受某些输入域。和以前一样,了解输入的所有使用方式。

处理来自 Web 服务器的响应:

确保您从 Web 服务器获得了 OK 状态。如果没有,请适当处理每个响应。一般来说,jquery.ajax 为您提供了使用 done、fail、always 和 statusCode 处理所有响应的选项,请参阅 jquery 文档以了解如何正确执行此操作。

你需要做的三件事:

  1. 在表单中使用 @Html.AntiforgeryToken() 及其相应的 [ValidateAntiForgeryTokenAttribute] 属性来装饰您的类和/或方法。

  2. 正确处理来自用户的输入。在数据被触及的任何地方,如果需要对其进行编码或参数化,或者以其他方式验证、约束或修改,则需要考虑上下文。

  3. 正确处理来自 Web 服务器的响应。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public sealed class ValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter { public Task< HttpResponseMessage > ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func< Task< HttpResponseMessage > > continuation) { try { AntiForgery.Validate(); } catch { actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.Forbidden, RequestMessage = actionContext.ControllerContext.Request }; return FromResult(actionContext.Response); } return continuation(); } private Task< HttpResponseMessage > FromResult(HttpResponseMessage result) { var source = new TaskCompletionSource< HttpResponseMessage >(); source.SetResult(result); return source.Task; } }

于 2014-10-03T00:41:24.190 回答