Fortify:跨站点脚本:反射

Posted

技术标签:

【中文标题】Fortify:跨站点脚本:反射【英文标题】:Fortify: Cross-Site Scripting: Reflected 【发布时间】:2019-10-13 15:01:51 【问题描述】:

我正在开发一个网络服务解决方案,我有以下代码来构建我的网络服务调用:

// Body portion
string postData = JsonConvert.SerializeObject(Body));
byte[] byteArray = Encoding.UTF8.GetBytes(postData);

// Send the query
webRequest.ContentLength = byteArray.Length;
Stream dataStream = webRequest.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

所以Body 将是一个 JSON 对象,我打算将它序列化,以便它可以表示为要发送到网络服务器的字符串。 但是用 Fortify 扫描的时候,报错原因是Cross-Site Scripting: Reflected,就在

dataStream.Write(byteArray, 0, byteArray.Length);

对于建议,尚不清楚修复方法是什么

建议:

XSS 的解决方案是确保在正确的位置进行验证并检查正确的属性。

由于当应用程序在其输出中包含恶意数据时会出现 XSS 漏洞,因此一种合乎逻辑的方法是在数据离开应用程序之前立即对其进行验证。但是,由于 Web 应用程序通常具有复杂而错综复杂的代码来生成动态内容,因此这种方法容易出现遗漏错误(缺少验证)。降低这种风险的一种有效方法是对 XSS 执行输入验证。

Web 应用程序必须验证其输入以防止其他漏洞,例如 SQL 注入,因此扩充应用程序的现有输入验证机制以包括对 XSS 的检查通常相对容易。尽管它很有价值,但 XSS 的输入验证并不能代替严格的输出验证。应用程序可以通过共享数据存储或其他受信任的源接受输入,并且该数据存储可以接受来自未执行充分输入验证的源的输入。因此,应用程序不能隐含地依赖此数据或任何其他数据的安全性。这意味着防止 XSS 漏洞的最佳方法是验证进入应用程序并将应用程序留给用户的所有内容。

验证 XSS 最安全的方法是创建允许出现在 HTTP 内容中的安全字符白名单,并接受仅由批准集中的字符组成的输入。例如,有效的用户名可能仅包含字母数字字符,或者电话号码可能仅包含数字 0-9。但是,这种解决方案在 Web 应用程序中通常是不可行的,因为许多对浏览器具有特殊含义的字符在编码后仍应被视为有效输入,例如必须接受来自其用户的 html 片段的 Web 设计公告板。

一种更灵活但安全性较低的方法称为黑名单,它在使用输入之前选择性地拒绝或转义具有潜在危险的字符。为了形成这样的列表,您首先需要了解对 Web 浏览器具有特殊含义的字符集。尽管 HTML 标准定义了哪些字符具有特殊含义,但许多 Web 浏览器试图纠正 HTML 中的常见错误,并可能在某些上下文中将其他字符视为特殊字符,这就是为什么我们不鼓励使用黑名单来防止 XSS 的原因。卡内基梅隆大学软件工程研究所的 CERT(R) 协调中心提供了以下有关各种上下文中特殊字符的详细信息 [1]:

在块级元素的内容中(在一段文本的中间):

“&”很特别,因为它引入了一个字符实体。

">" 是特殊的,因为一些浏览器认为它是特殊的,假设页面的作者打算包含一个开头的“

以下原则适用于属性值:

在用双引号括起来的属性值中,双引号是特殊的,因为它们标记了属性值的结束。

在用单引号括起来的属性值中,单引号是特殊的,因为它们标记了属性值的结束。

在不带引号的属性值中,空格和制表符等空白字符是特殊的。

“&”在与某些属性一起使用时是特殊的,因为它引入了一个字符实体。

例如,在 URL 中,搜索引擎可能会在结果页面中提供一个链接,用户可以单击该链接重新运行搜索。这可以通过在 URL 中编码搜索查询来实现,这会引入额外的特殊字符:

空格、制表符和换行符很特殊,因为它们标记了 URL 的结尾。

"&" 很特别,因为它要么引入字符实体,要么分隔 CGI 参数。

非 ASCII 字符(即 ISO-8859-1 编码中大于 128 的所有字符)都不允许出现在 URL 中,因此在此上下文中它们被视为特殊字符。

在任何使用 HTTP 转义序列编码的参数由服务器端代码解码的任何地方,都必须从输入中过滤“%”符号。例如,如果“%68%65%6C%6C%6F”等输入出现在相关网页上时变为“hello”,则必须过滤“%”。

在 a 的主体内:

在文本可以直接插入预先存在的脚本标签的情况下,应过滤掉分号、括号、花括号和换行符。

服务器端脚本:

将输入中的任何感叹号 (!) 转换为输出中的双引号字符 (") 的服务器端脚本可能需要额外的过滤。

其他可能性:

如果攻击者以 UTF-7 格式提交请求,特殊字符“

在您确定应用程序中执行 XSS 攻击验证的正确点以及验证应考虑哪些特殊字符之后,下一个挑战是确定您的验证如何处理特殊字符。如果特殊字符不被视为应用程序的有效输入,那么您可以拒绝任何包含特殊字符的输入为无效输入。在这种情况下,第二个选项是通过过滤删除特殊字符。但是,过滤具有改变过滤内容的任何视觉表示的副作用,并且在必须保留输入完整性以供显示的情况下可能是不可接受的。

如果必须接受并准确显示包含特殊字符的输入,则验证必须对任何特殊字符进行编码以消除其重要性。作为官方 HTML 规范 [2] 的一部分,提供了特殊字符的 ISO 8859-1 编码值的完整列表。

许多应用程序服务器试图通过为负责设置某些特定 HTTP 响应内容的函数提供实现来限制应用程序暴露于跨站点脚本漏洞,这些内容执行对跨站点脚本攻击必不可少的字符的验证。不要依赖运行应用程序的服务器来确保其安全。开发应用程序时,无法保证在其生命周期内将在哪些应用程序服务器上运行。随着标准和已知漏洞的发展,无法保证应用服务器也将保持同步。

我尝试输入HttpUtility.HtmlEncode,但这会弄乱字符串,因此不起作用。

有人知道怎么解决吗?

【问题讨论】:

取决于Body 是什么,它可能包含从简单文本到从客户端注入的恶意html 代码的所有内容。如何解决此问题取决于您期望的身体。无论如何,“弄乱一个字符串”可能很烦人,但你绝对应该这样做,除非你有更具体的原因表明这不起作用。 正文总是包含 json 格式的字符串。它不会包含 html 代码。 你怎么知道?如果您确定这一点,您可以忽略该警告。无论如何,我们不可能给你任何建议,因为你没有提供Body 是什么以及它来自哪里。 因为输入是由一组没有 HTML 代码的受控输入构成的。 那么你可以忽略这个警告。 Fortify 肯定无法知道您之前是否以某种方式保护您的输入。 【参考方案1】:

能够通过使用JSanitizer nuget package 方法来满足强化“跨站点脚本:反映”消息。包支持.NET Core 3.1。

    using JSanitizer;

    string serializedObj = JsonConvert.SerializeObject(myDynamic);
    documentResult.Content = serializedObj.SanitizeXmlValue();

【讨论】:

以上是关于Fortify:跨站点脚本:反射的主要内容,如果未能解决你的问题,请参考以下文章

加强跨站点脚本:糟糕的验证 JSF

XSS- 跨站点脚本:DOM 问题

PortSwigger 跨站点脚本(XSS)

跨站点脚本攻击(XSS)

如何针对跨站点脚本清理查询字符串输入 - 反映 ASP .Net(Web 窗体)应用程序中的问题?

跨站点脚本攻击