素材巴巴 > 程序开发 >

在.NET Core Web API中防止XSS

程序开发 2023-09-03 21:15:31

目录

等等,ASP.NET不会为我们处理这个问题吗?

嗯,废话。我们现在干什么?

你在开玩笑,对吧?

JSON转换器

ASP.NET中间件


在这篇文章中,您将看到一个关于如何(积极地)在您的API中防御XSS的建议。

你猜怎么着?如果您正在开发一个ASP.NET Web API项目并且没有采取措施来保护它免受XSS(跨站点脚本)的侵害,那么不幸的是,您手上有一个安全漏洞。

您可以在此处和此处的OWASP网站上阅读有关XSS(以及一些与平台无关的技术)的更多信息,但长话短说,XSS涉及您的API保存用户提交的包含恶意HTML或JavaScript的数据,并可能暴露另一个端点按原样返回数据。用户提交的脚本然后被返回到另一个用户的浏览器并以某种方式造成严重破坏——可能会破坏您的服务,从页面上抓取私人数据并通过网络发送,或者他们能想到的任何其他讨厌的东西.

现在,大多数现代浏览器和前端框架确实通常具有防止呈现不受信任的HTML的安全机制(例如,CSP和Angular的DomSanitizer),但这并不意味着我们应该只将安全责任委托给前端——后端; API也参与其中,并且应该受到保护。

等等,ASP.NET不会为我们处理这个问题吗?

它曾经(在一定程度上),所以我原谅你认为是这种情况。如OWASP 网站上所述,ASP.NET过去带有请求验证功能,该功能默认为Web表单(记住那些!)和MVC项目启用,但Web API项目从未支持此功能。可悲的事实是,现在绝大多数ASP.NET应用程序可能是API,因此我们不再可以使用请求验证,这很遗憾。在防止XSS方面,我们只能靠自己。

嗯,废话。我们现在干什么?

基本上有两种方法可以使用XSS;清理(​​或拒绝)输入,和/或编码输出。

推荐用于消毒的一个非常有信誉的软件包是HtmlSanitizer,它甚至列在OWASP网站上。基本用法如下所示:

var sanitizer = new HtmlSanitizer();
 sanitizer.AllowedAttributes.Add("class");
 var sanitized = sanitizer.Sanitize(html);

可以使用受支持的属性和标签的白名单配置杀毒程序(是的,这就是我的拼写方式),然后调用它以从源字符串中去除未列入白名单的属性和标签。虽然这个库是一个几乎一致推荐的包,但开箱即用它确实意味着您需要单独清理每个字段。

你在开玩笑,对吧?

可悲的是没有。您可以采取一些方法让杀毒程序在每个请求上运行,但据我所知,ASP.NET或包本身没有对此提供任何内置支持。我将为此向您展示几个示例,但是您可以通过从Github克隆它来下载并运行整个示例项目。

JSON转换器

对传入或传出API的内容进行清理的一种(尽管很简单)方法是使用自定义JSON转换器。为此,首先创建一个具有以下内容的新类(例如:AntiXssConverter):

public class AntiXssConverter : JsonConverter{public override string? Read(ref Utf8JsonReader reader,Type typeToConvert, JsonSerializerOptions options){var sanitiser = new HtmlSanitizer();var raw = reader.GetString();var sanitised = sanitiser.Sanitize(raw);if (raw == sanitised)return sanitised;throw new BadRequestException("XSS injection detected.");}public override void Write(Utf8JsonWriter writer, string value,JsonSerializerOptions options){writer.WriteStringValue(value);}}

请注意,此转换器基于.NET Core 3.1 及更高版本默认附​​带的System.Text.Json序列化程序。如果您使用Newtonsoft.Json转换器,则原理仍然相同,但实现可能会略有不同。

本质上,我们在这里所做的是提供一种策略,用于在反序列化JSON string时(例如:在模型绑定期间)读取字符串值并在序列化对象时(例如:当控制器返回响应时)写入string值。在这个特定的示例中,我们使用前面介绍的HtmlSanitizer包对每个string进行清理,如果清理string后的内容与原始包不同,我们会抛出一个自定义BadRequestException,以HTTP 400拒绝请求(由自定义异常处理中间件处理)。我们可以采取的另一种方法是简单地清理string并允许请求,或者按原样保存string并在Write方法中的序列化时对其进行清理(或编码)。

Startup.cs中,我们需要ConfigureServices(...)像这样注册转换器:

services.AddControllers().AddJsonOptions(options=>{options.JsonSerializerOptions.Converters.Add(new AntiXssConverter());});

这种方法适用于简单对象、嵌套对象和集合。但是,它确实有两个相当严重的缺点:

  1. 这个逻辑需要为请求中的每一个string运行。如果有效负载是一个具有许多string属性的大型对象,这可能会变得非常低效。
  2. 我们的XSS验证/清理与JSON耦合;如果用户要提交url编码的内容或multipart/form-data内容(如果我们有处理文件上传的端点,这可能是非常现实的情况),那么我们应用程序的其他部分可能仍然存在风险。

ASP.NET中间件

一种更高效、更通用的方法可能是通过中间件清理和验证整个请求体。这具有以下优点:

  1. 它只为每个请求运行一次——所以它应该比使用JSON转换器方法快得多。
  2. 它不与任何特定的内容类型耦合。无论端点使用JSON、formdata还是任何其他介质,请求仍将被清理和验证。

要实现这一点,请创建一个名为AntiXssMiddleware的新类,其内容如下:

public class AntiXssMiddleware
 {private readonly RequestDelegate _next;public AntiXssMiddleware(RequestDelegate next){_next = next;}public async Task Invoke(HttpContext httpContext){// enable buffering so that the request can be read by the model binders nexthttpContext.Request.EnableBuffering();// leaveOpen: true to leave the stream open after disposing,// so it can be read by the model bindersusing (var streamReader = new StreamReader(httpContext.Request.Body, Encoding.UTF8, leaveOpen: true)){var raw = await streamReader.ReadToEndAsync();var sanitiser = new HtmlSanitizer();var sanitised = sanitiser.Sanitize(raw);if (raw != sanitised){throw new BadRequestException("XSS injection detected from middleware.");}}// rewind the stream for the next middlewarehttpContext.Request.Body.Seek(0, SeekOrigin.Begin);await _next.Invoke(httpContext);}
 }

不要忘记在Startup.cs中的Configure(...)下注册它:

app.UseMiddleware();

如果您碰巧使用了自定义异常处理中间件,则需要在此之后注册。

在我们的中间件中,我们采用了与JSON转换器相同的方法来验证请求并在验证失败时抛出错误的请求异常。我发现这比JSON转换器快约50%,即使对于单字符串模型的人为示例也是如此。

无论如何,这只是关于如何(积极地)在您的API中防止XSS的一种建议。当然,这只是一个简单的示例——如果您正在构建任何类型的API需要传递HTML内容,例如CMS,您可能需要使用允许的标签和属性的白名单进行HtmlSanitizer配置。

https://www.codeproject.com/Articles/5313718/Preventing-XSS-in-NET-Core-Web-APIs


标签:

素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。