使用WebAPI时停止XSS

Tom*_*Tom 8 c# asp.net asp.net-mvc asp.net-4.0

我有一个接受的控制器

public class MyModel
{
   [MaxLength(400)]
   public string Message { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有一个WebApi Post Action

public HttpResponseMessage Post(MyModel viewModel)
{
            if (!ModelState.IsValid)
                return new HttpResponseMessage(HttpStatusCode.BadRequest);                 
            ...
}
Run Code Online (Sandbox Code Playgroud)

并采取行动.

由于内容是通过javascript写出的,而不是直接在视图中写出来的,确切的内容都被写出来了,也没有关于危险内容的asp.net警告.

我想要防范XSS.目前我在做

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

在Get动作中.(从使用C#正则表达式删除HTML标记中获取一些代码)

我应该使用Asp.Net内置的保护措施吗?我可以用我的模型装饰任何属性吗?

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

Sha*_*han 10

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

根据官方文档,您只需在您的web.config:

<httpRuntime encoderType="System.Web.Security.AntiXss.AntiXssEncoder" /> 
Run Code Online (Sandbox Code Playgroud)

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

更新:

事实证明,在 web.config 中设置编码器类型是不够的,我最终做的是拦截反序列化的 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: &, <, >, \", '");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用转换器:

config.Formatters.JsonFormatter.SerializerSettings.Converters = new List<JsonConverter>
{
    new AntiXssConverter()
};
Run Code Online (Sandbox Code Playgroud)

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

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

config.Formatters.JsonFormatter.SerializerSettings.StringEscapeHandling = 
    StringEscapeHandling.EscapeHtml;
Run Code Online (Sandbox Code Playgroud)

这涵盖了我的一切。

第二次更新:

我决定从使用 AntiXss 库更改为使用HtmlSanitizer,因为 AntiXss 对所有外来字符(ä、ö 等)进行编码的限制太多了,即使 unicode 块我也无法允许它们被列入白名单。

这个库的另一个好处是它使用 OWASP XSS 过滤器规避备忘单进行了单元测试。单击此处了解更多信息

第三次更新:

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

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

config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
Run Code Online (Sandbox Code Playgroud)

然后,为了在特定属性(例如密码字段)上忽略我的 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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

[JsonConverter(typeof(NoConverter))]
public string NewPassword { get; set; }
Run Code Online (Sandbox Code Playgroud)

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


Geo*_*ker 8

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

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

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

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

最好的办法是使用MicrosoftAntiXss库,并专门为GET和POST请求编码参数.

(我必须开始工作,但稍后我将发布更多代码以了解如何执行此操作).


小智 6

有两种主要思想可以防止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; }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.