AntiXSS в ядре ASP.Net
Microsoft Web Protection Library (AntiXSS) достигло конца жизни. На странице указано: "В .NET 4.0 версия AntiXSS была включена в фреймворк и может быть включена с помощью конфигурации. В ASP.NET v5 единственным кодировщиком будет только кодировщик с белым списком".
У меня есть классический сценарий сценариев сценариев: решение ASP.Net Core, в котором пользователи могут редактировать текст, используя HTML-редактор WYSIWYG. Результат отображается для просмотра другими. Это означает, что если пользователи вводят JavaScript в данные, которые они отправляют при сохранении текста, который этот код может выполнять, когда другие посещают страницу.
Я хочу иметь белый список определенных HTML-кодов (безопасных), но вырезать плохие коды.
Как мне это сделать? Я не могу найти какие-либо методы в ASP.Net Core RC2, чтобы помочь мне. Где этот кодировщик белого списка? Как его вызвать? Например, мне нужно будет очистить вывод, возвращаемый через JSON WebAPI.
Ответы
Ответ 1
В главном сообществе dot.net есть wiki.
Вы можете вводить кодировщики на уровне контроллера (в конструкторе) или в качестве ссылки System.Text.Encodings.Web
.
Больше информации можно увидеть здесь:
https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting
Ответ 2
Чтобы выполнить автоматическую проверку Xss, старый MVC использовал логику, реализованную в классе System.Web.CrossSiteScriptingValidation. Однако этот класс отсутствует в ASP.NET CORE 1. Поэтому, чтобы повторно использовать его, я скопировал его код:
System.Web.CrossSiteScriptingValidation class
// <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 the last char, it safe
if (n == s.Length - 1) return false;
matchIndex = n;
switch (s[n])
{
case '<':
// If the < is followed by a letter or '!', it 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 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
}
Чем, чтобы использовать вышеприведенный класс для всех запросов, я создал Middleware, которые используют класс CrossSiteScriptingValidation:
AntiXssMiddleware
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;
}
}
Ответ 3
Вы можете использовать System.Text.Encodings.Web для программного кодирования в .NET Standard. Он предлагает кодировщики HTML, JavaScript и URL. Это должно быть эквивалентно AntiXss, потому что задокументировано использование белого списка:
По умолчанию кодировщики используют безопасный список, ограниченный диапазоном базового латинского Unicode, и кодируют все символы за пределами этого диапазона в качестве эквивалентов кодов символов.
Ответ 4
Похоже, вам нужен какой-то дезинфицирующее средство с белым списком. OWASP AntiSamy.NET делал это, но я больше не думаю, что он поддерживается.
Если данные всегда доставляются в JSON, вы также можете запустить через DOMPurify на стороне клиента, прежде чем добавлять его в DOM. Наличие вредоносного HTML в самом JSON не так уж и опасно (по крайней мере, не до тех пор, пока вы правильно задали параметры типа содержимого и X-content-type: nosniff). Код не будет запускаться до тех пор, пока он не будет отображаться в DOM.
Ответ 5
Это хороший вопрос. Я хочу отметить одну вещь: мы никогда не должны пытаться создать собственное дезинфицирующее средство. Их очень сложно понять правильно. Гораздо лучше использовать библиотеку, созданную и поддерживаемую авторитетным автором.
Из OWASP: "OWASP рекомендует использовать ориентированную на безопасность библиотеку кодирования, чтобы убедиться, что эти правила правильно реализованы".
Если вы используете .NET Framework, эта библиотека все еще может подойти: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.antixss.antixssencoder?view=netframework-4.8
Для .NET Core также может помочь библиотека System.Text.Encodings, как указано выше. https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting?view=aspnetcore-2.2#accessing-encoders-in-code
Ответ 6
Если вы действительно хотите обезопасить ввод, то есть разрешить только определенный набор элементов HTML, простое кодирование контента не сильно поможет. Вам нужно средство для дезинфекции HTML.
Создание такой вещи - нелегкая задача. Вам понадобится какой-то метод для анализа HTML и набор правил о том, что разрешить, а что нет. Чтобы в будущем новые HTML-теги не вызывали проблем с безопасностью, я рекомендую использовать белый список.
Существует по крайней мере две открытые HTML-библиотеки для санитарии, которые работают на .NET Core, одну из которых я написал несколько лет назад. Оба доступны в виде пакетов NuGet:
Они используют различные HTML-разборки в качестве серверной части. Возможно, вам придется немного настроить наборы правил, чтобы они соответствовали тому, что создает ваш редактор WYSIWYG.