一群从事绝密项目而不自知的JavaScript开发人员,该用什么样的方法来提取他们的代码呢?本文的故事就是关于这个的。这些技术之所以有效,是因为浏览器在不需要多重防护的条件下就允许公共来源的websockets打开本地主机的websockets连接。
这让笔者产生了一些思考。笔者知道流行的JavaScript框架在开发中使用websockets,以在内容更改时自动重新加载页面。一个恶意的网站能不能窃听到这些流量,并找出开发人员在何时保存下的代码?
事实比想象的还要糟糕。
计划如下:
· 进行一些设置,或是将广告恶意软件注入前端开发人员经常访问的热门网站。比如说
http://frontend-overflowstack.com/
· 在此页上,添加尝试打开到公共端口的websockets连接的代码(扫描10k端口大致需要一秒钟,因此可以在这里轻松实现此功能)
· 如果页面成功打开连接,请保持打开状态,并将收到的所有消息转发到自己的秘密数据库。
计划生效了吗?
一个非常简单的页面就能验证:http://frontend overflowstack.com/。加载时,它会尝试将websocket连接到访客计算机上2000到10000之间的每个端口(除了Firefox不允许的几个端口)。
如果某个端口连接,它将侦听该端口输出接收到的任何消息。此页不会保存或传输任何捕获的数据,仅在屏幕上临时显示。如果此页上出现任何输出,则实际恶意站点可以很容易地将该输出发送到其所需的任何服务器。
生成数据
为了测试这个概念,我需要一个简单的使用热加载的web服务器:
- var express =require('express')
- var http =require('http')
- var path =require('path')
- var reload =require('reload');
- var app = express()
- app.get('/', function (req, res) {
- res.sendFile(path.join(__dirname, 'public', 'test.html'));
- })
- var server = http.createServer(app)
- reload(app).then(function(reloadReturned) {
- server.listen(3000, function () {});
- setInterval(reloadReturned.reload, 5000);
- });
当运行时,它会启动端口3000上的服务器,端口9856上的websocket服务器,并发送一条消息:每5秒重新加载(reload )链接所有websocket的客户端。如果启动嗅探器站点,将显示以下内容:
因此,前端overflowstack.com可直接窃听重载消息,这些消息从本地开发服务器发送到本地浏览器。在这个阶段,我们可以坐下来数一数每个访问我们网站的人对本地JavaScript代码进行了多少次更改。
但是,可以用这种方式来获取更多信息吗?
情节更复杂了
目前大多数的前端开发似乎都会使用React,通常这涉及到运行webpack dev服务器,其中包括它自己的,以及更繁多的web socket接口。该服务器通过其websocket可共享更多数据,只是更有趣些:
- $ npxcreate-react-app test
- $ cd test/
- $ npm start
运行这些代码之后,再来看看我们的恶意网站:
马上就会有更多的数据显示出来,得到散列式和状态式的消息,以及所有无用的信息。当开发人员输入错误时,会发生什么?webpack dev服务器通过其websocket连接,尝试将一堆调试和堆栈信息发送到开发人员的屏幕上。这些信息在恶意网站也能看到:
现在,我们有了代码片段、文件路径、位置等各种有用的信息。甚至当开发人员最终意外地在包含有用数据的代码行上键入错误时,得到的结果会更好:
现在你可获得一份开发人员的AWS开发人员证书副本。
没有图表,任何技术设计都是不完整的。这里展示了图像化的代码运行:
为了简化图表,此处省略了正在运行的本地web服务器,并假设websocket服务器直接来自于编辑器中。
某些浏览器选项卡上的恶意网页会自动连接到用户计算机上打开的WebSocket。当敏感数据通过该套接口发送时(从希望通过仅本地通道进行通信的进程发送),网站可以接收该消息数据,并将其转发到任何外部数据库。
限制因素
值得注意的是,该攻击向量很小。必须诱使不知情的用户访问网站,并在他们开发JS代码时继续使用它。然后,必须等待在较为幸运的情况下从他们的编码错误中收集一些数据,这也许有助于找到从这些数据中获利的突破口。
综合考虑
然而,许多网站已经在使用websocket端口扫描技术,而没有太多开发人员能意识到这一点。考虑到JS工具倾向于使用那些众所周知的端口的小部分,编写一个脚本来巧妙地过滤react Dev通信量并不是特别困难。
想象一下,一个为Twitbook工作的内部开发人员只需在其编辑器中按save键,就会导致访问令牌或内部服务器地址被泄露给错误的访问者。
这有点吓人,正常开发人员通常会希望在他们选择的代码编辑器中按下save键时,是不会将数据泄漏到第三方web服务的。而这增加了这种风险,足以让人有点担心。
补救
笔者的建议是这种尝试拦截JavaScript热加载机制的方法,它是笔者所熟悉的websockets的唯一通用方法。Discord也使用websockets,但匆匆一瞥并不会产生任何明显的效果,因为该通道以公共互联网为设计目标。
令人担忧的是,仅仅这一个用于重新加载的单向通信简单用例,就将如此多的潜在信息暴露给了那些恶意网站。websockets的其他用途(对于不是为公共互联网设计的数据)也可能受到类似的威胁。
争论在于,webpack dev服务器应该进行一些身份验证,或者使用备用的浏览器通信通道进行热重载。浏览器/web标准为websockets实现源代码策略的方式无疑令人惊讶。导致那些专为本地开发而设计的软件以一种难以预料的方式暴露在公共互联网上。
很期待针对浏览器中额外控制功能部分的修复。