我有一个接受
的控制器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/似乎非常糟糕。
答案 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服务器获得了OK状态。如果您没有,请适当地处理每个响应。通常,jquery.ajax为您提供了处理所有响应的选项,包括done,fail,always和statusCode,请参阅jquery文档,了解如何正确执行此操作。
在表单中使用@ Html.AntiforgeryToken()及其相应的[ValidateAntiForgeryTokenAttribute]属性来装饰您的类和/或方法。
正确处理来自用户的输入。无论何处触摸数据,都需要考虑上下文,如果需要对其进行编码或参数化,或者进行其他验证,约束或修改。
正确处理来自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;
}
}