Ted*_*sen 12 xss asp.net-core-1.0
Microsoft Web Protection Library(AntiXSS)已达到使用寿命终止.该页面指出"在.NET 4.0中,AntiXSS的一个版本包含在框架中,可以通过配置启用.在ASP.NET v5中,基于白名单的编码器将是唯一的编码器."
我有一个经典的跨站点脚本方案:一个ASP.Net Core解决方案,用户可以使用WYSIWYG html编辑器编辑文本.显示结果供其他人查看.这意味着如果用户在保存文本时将JavaScript注入其提交的数据中,则此代码可在其他人访问该页面时执行.
我希望能够将某些HTML代码(安全的代码)列入白名单,但删除不良代码.
我该怎么做呢?我在ASP.Net Core RC2中找不到任何方法来帮助我.这个白名单编码器在哪里?我该如何调用它?例如,我需要清理通过JSON WebAPI返回的输出.
dot.net 核心社区对此有一个 wiki。
您可以在控制器级别(在构造函数中)或引用注入编码器System.Text.Encodings.Web。
更多信息可以在这里看到:
https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting
为了执行自动Xss检查,旧的 MVC 使用了System.Web.CrossSiteScriptingValidation类中实现的逻辑。但是,ASP.NET CORE 1 中不存在此类。因此,为了重用它,我复制了它的代码:
// <copyright file="CrossSiteScriptingValidation.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
public static class CrossSiteScriptingValidation
{
private static readonly char[] StartingChars = { '<', '&' };
#region Public methods
// Only accepts http: and https: protocols, and protocolless urls.
// Used by web parts to validate import and editor input on Url properties.
// Review: is there a way to escape colon that will still be recognized by IE?
// %3a does not work with IE.
public static bool IsDangerousUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return false;
}
// Trim the string inside this method, since a Url starting with whitespace
// is not necessarily dangerous. This saves the caller from having to pre-trim
// the argument as well.
s = s.Trim();
var len = s.Length;
if ((len > 4) &&
((s[0] == 'h') || (s[0] == 'H')) &&
((s[1] == 't') || (s[1] == 'T')) &&
((s[2] == 't') || (s[2] == 'T')) &&
((s[3] == 'p') || (s[3] == 'P')))
{
if ((s[4] == ':') || ((len > 5) && ((s[4] == 's') || (s[4] == 'S')) && (s[5] == ':')))
{
return false;
}
}
var colonPosition = s.IndexOf(':');
return colonPosition != -1;
}
public static bool IsValidJavascriptId(string id)
{
return (string.IsNullOrEmpty(id) || System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(id));
}
public static bool IsDangerousString(string s, out int matchIndex)
{
//bool inComment = false;
matchIndex = 0;
for (var i = 0; ;)
{
// Look for the start of one of our patterns
var n = s.IndexOfAny(StartingChars, i);
// If not found, the string is safe
if (n < 0) return false;
// If it's the last char, it's safe
if (n == s.Length - 1) return false;
matchIndex = n;
switch (s[n])
{
case '<':
// If the < is followed by a letter or '!', it's unsafe (looks like a tag or HTML comment)
if (IsAtoZ(s[n + 1]) || s[n + 1] == '!' || s[n + 1] == '/' || s[n + 1] == '?') return true;
break;
case '&':
// If the & is followed by a #, it's unsafe (e.g. S)
if (s[n + 1] == '#') return true;
break;
}
// Continue searching
i = n + 1;
}
}
#endregion
#region Private methods
private static bool IsAtoZ(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
然后,为了对所有请求使用上述类,我创建了一个使用CrossSiteScriptingValidation类的中间件:
public class AntiXssMiddleware
{
private readonly RequestDelegate _next;
private readonly AntiXssMiddlewareOptions _options;
public AntiXssMiddleware(RequestDelegate next, AntiXssMiddlewareOptions options)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
_next = next;
_options = options;
}
public async Task Invoke(HttpContext context)
{
// Check XSS in URL
if (!string.IsNullOrWhiteSpace(context.Request.Path.Value))
{
var url = context.Request.Path.Value;
int matchIndex;
if (CrossSiteScriptingValidation.IsDangerousString(url, out matchIndex))
{
if (_options.ThrowExceptionIfRequestContainsCrossSiteScripting)
{
throw new CrossSiteScriptingException(_options.ErrorMessage);
}
context.Response.Clear();
await context.Response.WriteAsync(_options.ErrorMessage);
return;
}
}
// Check XSS in query string
if (!string.IsNullOrWhiteSpace(context.Request.QueryString.Value))
{
var queryString = WebUtility.UrlDecode(context.Request.QueryString.Value);
int matchIndex;
if (CrossSiteScriptingValidation.IsDangerousString(queryString, out matchIndex))
{
if (_options.ThrowExceptionIfRequestContainsCrossSiteScripting)
{
throw new CrossSiteScriptingException(_options.ErrorMessage);
}
context.Response.Clear();
await context.Response.WriteAsync(_options.ErrorMessage);
return;
}
}
// Check XSS in request content
var originalBody = context.Request.Body;
try
{
var content = await ReadRequestBody(context);
int matchIndex;
if (CrossSiteScriptingValidation.IsDangerousString(content, out matchIndex))
{
if (_options.ThrowExceptionIfRequestContainsCrossSiteScripting)
{
throw new CrossSiteScriptingException(_options.ErrorMessage);
}
context.Response.Clear();
await context.Response.WriteAsync(_options.ErrorMessage);
return;
}
await _next(context);
}
finally
{
context.Request.Body = originalBody;
}
}
private static async Task<string> ReadRequestBody(HttpContext context)
{
var buffer = new MemoryStream();
await context.Request.Body.CopyToAsync(buffer);
context.Request.Body = buffer;
buffer.Position = 0;
var encoding = Encoding.UTF8;
var contentType = context.Request.GetTypedHeaders().ContentType;
if (contentType?.Charset != null) encoding = Encoding.GetEncoding(contentType.Charset);
var requestContent = await new StreamReader(buffer, encoding).ReadToEndAsync();
context.Request.Body.Position = 0;
return requestContent;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您确实希望清理输入,即只允许使用特定的 HTML 元素集,那么简单地对内容进行编码并没有多大帮助。您需要一个 HTML 清理器。
建造这样的东西并不是一件容易的事。您需要一些方法来解析 HTML 以及一组允许通过和不允许通过的规则。为了防止将来的新 HTML 标签引起安全问题,我建议采用白名单方法。
至少有两个可在 .NET Core 上运行的开源 HTML 卫生库,其中一个是我几年前编写的。两者都以 NuGet 包的形式提供:
他们使用不同的 HTML 解析作为后端。您可能需要稍微调整规则集以匹配所见即所得编辑器创建的内容。
听起来您需要某种基于白名单的消毒剂。OWASP AntiSamy.NET 曾经这样做过,但我认为它不再被维护了。如果数据始终传递为 JSON,您还可以在将其添加到 DOM 之前在客户端通过 DOMPurify 运行。JSON 本身中包含恶意 HTML 并不是那么危险(至少只要您正确设置了 content-type 和 X-content-type-options: nosniff 标头)。该代码在渲染到 DOM 中之前不会触发。
| 归档时间: |
|
| 查看次数: |
8912 次 |
| 最近记录: |