注意:请阅读整个答案,我从 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; }
我可能仍然错过了一些东西,我绝不是专业的网络开发人员,但这是一次有趣的旅程...... :-)