不久前,独立软件开发人员 Tim Perry,用于拦截和调试 Web 流量的HTTP 工具包的创建者决定为他的产品添加代理支持,就像现在的许多软件一样,它是使用Node.js
.
ICYMINode.js
是一个项目,它将 JavaScript 语言从您的浏览器中分离出来,并将其本身变成了一个成熟的应用程序开发系统,有点像 Java(顺便说一下,它与 JavaScript 无关,因为所有名称听起来很像)。
除了使用谷歌 Chromium 项目的 V8 JavaScript 引擎的 JavaScript 核心外,Node.js
软件通常还依赖NPM、Node 包管理器和NPM 注册表,这是一个真正庞大的开源 Node 工具和编程库存储库。
NPM 注册表从基本的文本格式到全面的面部识别,以及介于两者之间的几乎所有内容。
无需自己编写项目中的所有代码,甚至大部分代码,您只需引用要使用的附加包,NPM 将为您获取它们,以及您选择的包需要的任何其他包,以及这些包需要的所有包,一直跟随海龟包,直到完成拼图所需的每一段附加代码都已被自动找到并安装。
字母汤
可以想象,这是一个潜在的安全噩梦。
将一个包添加到您自己的项目中可能需要大量额外的包,每个包都可能由您不认识、从未见过甚至可能永远不会认识的不同人编写。
这个字母汤被称为您的软件的依赖树,我们之前已经写过这种软件构建方法的风险副作用,并指出:
您可能会发现您可以编写一个优雅简单的五行 JavaScript 程序,但前提是您的 Node Package Manager 拖入了数十甚至数十万行其他人的软件。自动地。来自整个互联网。并保持更新。自动,来自整个互联网。
代理支持带来麻烦
Perry 最近重新发现了这种风险,当时他决定使用一个流行的 NPM 包Proxy-Agent
来提供他想要的 HTTP Toolkit 产品中的代理支持。
幸运的是,Perry 并没有盲目地获取、安装和开始使用Proxy-Agent
它的整个依赖树,而没有对他的项目中新获得的组件进行审查。
因此,他在名为 的Proxy-Agent
依赖项中发现了一个安全漏洞,现在称为 CVE-2021-23406,该依赖项Pac-Resolver
是一个子组件,可帮助您的代码处理 PAC 或代理自动配置过程(请参阅下面的边栏)。
代理服务器是代表您进行传出连接的服务器,通常是为了安全(例如过滤网络流量)、性能(例如保留经常下载的文件的本地副本,或在繁忙时段调节带宽使用),或对彼此而言。您连接到代理并告诉它您想去哪里;它为您建立向前的联系,收集回复,并将它们返回给您。许多公司网络都配置为某些出站连接,尤其是 HTTP 请求,只能来自指定的代理服务器。这确保网络内的每个人都通过代理发送他们的流量,而不是直接转到外部站点。存在许多企业风格的工具来帮助网络上的计算机自动定位其官方内部代理,包括 PAC,简称为代理自动配置和 WPAD,Web 代理自动发现的缩写。
信不信由你
不管你信不信,PAC 文件不仅仅是网络官方代理服务器所在的 IP 号码或服务器名称的纯数据列表。
因为它们旨在在您的浏览器中摄取和使用,所以 PAC 文件被有意设计为比静态数据列表更灵活。
事实上,PAC 文件由 JavaScript 组成,可以动态确定是否需要代理,如果需要,可以在网络上的何处找到它。
正如 Perry 所指出的,PAC 文件格式可以追溯到 25 年前,并且首次作为 Netscape 浏览器中的“功能”出现:
PAC 文件提供了一种分发复杂代理规则的方法,作为将各种 URL 映射到不同代理的单个文件。它们在企业环境中广泛使用,因此通常需要在可能在企业环境中运行的任何软件中得到支持。[... PAC 文件是] 您必须执行才能连接到 Internet 的 JavaScript 文件,该文件是远程加载的,通常不安全和/或从可以由本地网络静默决定的位置加载。1996 年确实是一个简单的时期。什么可能出错?
当然,Perry 并不打算在浏览器的有限限制内运行 PAC 文件,但作为他的 HTTP Toolkit 软件的一部分,它作为常规应用程序运行,这可能会给它启动的 JavaScript 提供比脚本更大的影响力和功能代码会在浏览器中享受。
因此,他决定看看他选择的代理配置代码的程序员如何解决获取和运行外部 JavaScript 的安全隐患。
他发现该代码使用了一个名为 的 Node 组件vm
,虚拟机的缩写,它允许您设置一个新的 JavaScript 实例或状态,您不会干扰在应用程序中其他 Node 实例中运行的代码。
如果您想让代码的两个部分以不会错误地相互践踏的方式做单独的事情,这是一个方便的预防措施。
用vm
图书馆文档的话来说:
该
vm
模块支持在 V8 虚拟机上下文中编译和运行代码。[…] JavaScript 代码可以立即编译并运行,也可以编译、保存并稍后运行。一个常见的用例是在不同的 V8 上下文中运行代码。这意味着被调用代码与调用代码具有不同的全局对象。
安全是好的,但安全性更好
Perry 意识到,原来的程序员(他现在采用了他的代码)使用该vm
库的次数与程序安全性和安全性一样多,显然假设新vm
实例不仅与vm
应用程序中的其他实例分开,而且在其内部被严格沙箱化。自己的小僻静 JavaScript 世界。
但是,正如vm
文档所明确指出的那样,以粗体字显示:
该
vm
模块不是一种安全机制。不要使用它来运行不受信任的代码。
Perry 很快就想出了如何使用常规 JavaScript 编程技术在新vm
实例中运行代码,该实例可以完全访问其主Node.js
应用程序的外部数据。
从技术上讲,这构成了代理配置过程中的 RCE 错误,其中 RCE 是远程代码执行的缩写。
粗略地说,RCE 意味着从不受信任的来源获取的不受信任的内容可以故意做一些不应该被允许的危险行为,而不会首先出现任何警告或弹出对话框。
这真的有问题吗?
正如 Perry 发现的一些评论者指出的那样,利用此漏洞通常意味着更改专用网络的官方代理 PAC 文件以包含诱杀的 JavaScript。
但是,如果您已经有权更改组织的代理设置,那么无论如何您都可以简单地将网络上的每个人重定向到假代理,无论是否存在任何 JavaScript 错误……
……如果您可以默默地重定向网络上的每个浏览器,那么您肯定已经拥有足够多的网络犯罪控制来对组织造成严重破坏吗?
因此,一些评论者认为,CVE-2021-23406 只不过是茶杯中的风暴。
除了通过虚假代理重定向每个人的浏览器(尽管最终可能存在风险)之外,还不如作为代理配置的副作用在网络上的每台计算机上运行任意程序的能力那么危险……
...同时保持原始代理配置不变,因此其他一切似乎仍然照常工作
通过公开重新配置每台计算机以开始使用不同的代理服务器来入侵网络更有可能产生麻烦的副作用,这些副作用会引起注意、报告和调查。
当代的网络骗子喜欢通过避免普通用户可能注意到的变化来保持“低调”,即使他们没有注意网络安全事件。
该怎么办?
- 你有什么Node.js的软件使用
Pac-Resolve
,Pac-Proxy-Agent
或Proxy-Agent
?如果是这样,请确保您拥有这些软件包的 5.0.0 或更高版本。 - 您是否定期审查
Node.js
您的产品所依赖的许多模块?如果没有,请制定计划。这意味着在您的软件发布过程中考虑额外的时间和专业知识。快速行动并打破常规可能是原型和内部实验的有用座右铭,但它是构建运输产品的鲁莽方式。 - 您是否探索过您使用的库的安全限制?如果没有,那么你应该这样做。创建一个新的 JavaScript VM 实例听起来好像应该提高安全性,因为每个“虚拟机”都是单独运行的,但这与在安全控制的沙箱或围墙花园中运行不同 - 文档清楚地说明了这一点。
- 您是否认为广泛使用的软件包可以被视为安全的?如果是这样,那就不要。CVE-2021-23406 不是在常规使用中可能出现的那种错误,不像缓冲区溢出可能会通过意外崩溃暴露自己。有些错误只是因为有人决定仔细查看才被发现,就像 Tim Perry 在这里所做的那样。
就其价值而言,Perry 指出,这个故事中的软件包每周会收到大约 3,000,000 次下载,因此仅靠受欢迎程度并不能保证正确性。
永远不要忘记,当涉及到此类所谓的供应链错误时,您可以外包编码,但不能外包责任。
文章by Paul Ducklin