2024年七大最佳免费货币转换API
NodeJS XML外部实体指南:示例及预防
使用 XML 和 JSON 等标记语言是网络上相当标准的做法。借助这些技术,管理和交付人可读和机器可读的数据都非常简单和透明。因此,在网站和平台上很常见。然而,必须意识到滥用 XML 等技术可能会给您的平台带来的潜在风险和漏洞。
XML 外部实体就是这样一个漏洞。在本文中,我们将介绍它们是什么,向您展示如何发现这些漏洞,并演示如何保护您的 NodeJS 应用程序免受这些漏洞的侵害。
我们想提醒您,如果您没有使用 NodeJS 的经验,您可能很难从本文中获益。因此,我们强烈建议您浏览这篇 NodeJS 简介。我们将讨论一些元素,除非您具备 JavaScript 和 NodeJS 的背景知识,否则您可能不会立即明白这些元素。
现在,这个问题已经解决了,我们开始吧。
定义 XML 外部实体
那么,什么是 XML 外部实体?
XML,即可扩展标记语言,是一种用于存储、传输和重建任意数据的标记语言和文件格式。此外,这种语言还用于编程领域,定义以人机可读格式对文档进行编码的规则。
XML 文件结构如何造成漏洞?默认情况下,大多数 XML 处理工具允许指定外部实体。此实体(通常是 URI)在解析 XML 文件时被检索和处理。发生这种情况时,解析器可以请求并包含 XML 文档中指定 URI 处的内容。
此漏洞使系统面临被利用的风险。恶意攻击者可以利用此属性作为获取服务器上任何资源的途径。因此,XML 外部实体攻击(或 XXE 注入)利用了 XML 解析漏洞。它针对使用面向用户的 XML 解析功能的系统,允许攻击者访问服务器上的文件和资源。
攻击可能包括泄露包含敏感数据(例如密码或私人用户数据)的本地文件,以及在系统标识符中使用文件:方案或相对路径。显然,一个有决心的攻击者可能会接管您的服务器,尤其是在充分了解服务器结构和一些有关您的技术堆栈的信息的情况下。
XML 外部实体的示例
现在您对 XXE 注入有了基本的了解,让我们来看一个例子。这是一个包含用户名 XML 元素的示例 XML 文档:
<?xml version="1.0" encoding="ISO-8859-1"?>
<username>John</username>
</xml>
非常无害且简单,对吧?外部实体在哪里?
首先,可以使用 DOCTYPE 标头内的系统标识符添加外部 XML 实体。此标头基本上为 XML 文件结构添加了几个属性。
例如,下面的代码包含一个外部 XML 实体,它将获取 /etc/passwrd 的内容并将其显示给按用户名呈现的用户:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwrd" >]>
<username>&xxe;</username>
</xml>
哎呀!
这些实体可以访问您服务器中的本地或远程内容,如果您在服务器上保存敏感文件,这将非常糟糕,因为它们可能会为攻击者提供控制您网站的途径。
类似地,其他 XML 外部实体攻击可以访问本地资源,并且可能不会止步于返回数据。因此,这也是影响应用程序可用性并导致拒绝服务的途径。
缓解 XML 外部实体漏洞
幸运的是,缓解 XML 外部实体漏洞相对简单。只要您不是故意尝试打开漏洞窗口,并且认为您需要用户提供的 XML 文件的功能,您就不必太担心。
如前所述,如果应用程序具有解析 XML 文件的端点,攻击者可以向服务器发送特制的有效负载并获取敏感文件。攻击者可以访问的文件在很大程度上取决于您如何设置系统以及如何实现用户权限。因此,为了防止这种情况,首先,不要使用支持实体替换的库,如 LibXML。
遗憾的是,NodeJS 没有内置 XML 解析引擎。您可能已经在项目中使用此库。但不要担心 – 默认情况下禁用实体替换。尽管如此,我们建议您明确禁用此功能。您可以通过简单地更改库的所有初始化来做到这一点,如下所示:
const lib = libxmljs.parseXml(xml, {noent: true});
还需要牢记的是,如果您决定采用这种方式,您仍然可能容易受到 DDoS 攻击。
现在,假设您的应用程序实际上利用外部实体来实现某些关键功能。在这种情况下,您可以采取一种方法来最大限度地降低漏洞利用的可能性,那就是将已知的外部实体列入安全列表。您只需在使用库解析 XML 文件文档之前检查其中是否有包含不在列表中的任何实体的字符串即可。
app.post('/load_xml', upload.single('xml'), async function (req, res) {
if (!req.file) {
res.sendStatus(500);
return;
}
try {
const xml = req.file.buffer;
const doc = libxmljs.parseXml(xml, {noent: true});
if (doc.text().includes("<!ENTITY")) {
throw new Error("INVALID XML FILE");
}
res.send(doc.text());
} catch (err) {
res.send(err.toString());
res.sendStatus(500);
}
});
最后
最后——我想强调这一点——如果应用程序不需要解析 XML,请不要解析。我知道解析 XML 可能会很方便,并允许平台为用户提供便捷的功能。即便如此,仍有许多方法可以在不使用这些库的情况下提供类似的功能。
最后,最好的缓解策略是绝不要对漏洞敞开大门。务必记住,为用户提供强大而安全的平台正变得越来越复杂。这样的工作需要投入大量的时间和专业知识,而您的组织可能无法承担。
结论
保护您的平台免受网络上最复杂的攻击需要对技术有广泛的了解,并牢牢掌握平台的基础架构。值得庆幸的是,用于构建基础架构的大多数工具和库都非常强大和安全。无论如何,工程师无意中引入漏洞并危及团队工作的可能性始终存在。
文章来源:NodeJS XML External Entities Guide: Examples and Prevention