使用Web API时停止XSS

时间:2012-09-27 09:41:05

标签: c# asp.net asp.net-mvc asp.net-4.0

我有一个接受

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

我有一个WebApi Post Action

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))
Get操作中的

。 (从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/似乎非常糟糕。

5 个答案:

答案 0 :(得分:6)

正如您的代码现在所处,用户可以注入不使用脚本标记的JavaScript。

可以使用common list个XSS漏洞。

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

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

最好的办法是使用AntiXss library from Microsoft,并专门为GET和POST请求编码参数。

(我必须开始工作,但稍后我会发布更多关于如何执行此操作的代码。)

答案 1 :(得分:6)

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

  • 输出编码
  • 输入验证

对于输出编码,Server.HtmlEncode(p.message)应该可以解决问题(因此您的示例中的当前内容将起作用,如果您不想,则不需要进行Regex替换。输出编码将阻止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; }
}

希望这有帮助。

答案 2 :(得分:2)

根据官方documentation,您可以在web.config中执行以下操作:

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

由于现在已包含在.NET 4.5中,因此您不再需要安装AntiXss库。

更新:

结果证明,仅在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过滤器逃避备忘单进行了单元测试。 Click here for more info

第三次更新:

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

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

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

然后,为了忽略我的XSS转换器的特定属性(例如,例如“密码”字段),我从following answer找到了一个很好的解决方案,该解决方案是创建一个虚拟的“ 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; }

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

答案 3 :(得分:1)

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

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

在此链接中,所有步骤都已涵盖,请完成并执行。

将中间件添加到 Startup.cs 类面临的唯一问题。

app.UseAntiXssMiddleware();

我没有使用下面的语法在 Startup.cs 类中添加中间件。

app.UseMiddleware<AntiXssMiddleware>();

答案 4 :(得分:-3)

防止网络安全方面的缺陷:

尽量减轻伤害。使用防伪令牌,确保您只接受ssl进行某些操作。确保cookie得到适当保护。总的来说,尽量减少攻击面并设置障碍使其变得更难。

防止用户输入:

参数化用户输入,如果您不能进行参数化,编码,但在编码时要非常小心,许多漏洞都是由不正确的编码引起的。编码还取决于输入的使用位置和方式。   约束并验证用户输入,确保服务器仅接受某些输入域。和以前一样,了解输入的所有使用方式。

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

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

您需要做的三件事:

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

  2. 正确处理来自用户的输入。无论何处触摸数据,都需要考虑上下文,如果需要对其进行编码或参数化,或者进行其他验证,约束或修改。

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

  4. [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; } }