[Security] 无鉴权 WebSocket 服务可窃取自动化浏览器的全部会话 Cookie(端口 8084)

Author: 28HusCreated Aug 10, 2026Updated Aug 10, 2026

1. 摘要

EasySpider 的 Electron 主进程在 8084 端口运行一个无鉴权、不校验来源(Origin)、且默认绑定所有网卡的 WebSocket 服务(ElectronJS/main.js:1270)。任意攻击者只要能够连接该端口,即可通过两步消息协议:

  1. 发送 {"type":0,"message":{"id":2}} 将自己的连接注册为 socket_flowchart
  2. 发送 {"type":7} 触发服务端读取正在自动化的浏览器当前会话的全部 Cookie 并回传。

从而窃取受害者在第三方网站上已登录的会话 Cookie,实现身份冒用。该问题已在本地环境用真实 Chrome 完成动态验证(见 §6)。

2. 受影响组件与版本

项目
仓库 https://github.com/NaiboWang/EasySpider
组件 ElectronJS/main.jsElectronJS/package.jsonmain 字段,生产入口)
版本 0.6.3
测试 commit 191bd6d7547bb397e4c579dd2c70ae835be3f512(master,2026-07-03)
漏洞端口 8084(main.js:57 硬编码)
CWE CWE-306(关键功能缺少认证)、CWE-200(敏感信息暴露给未授权方)、CWE-346(来源校验错误)
严重度 High(利用前提见 §5)

3. 根因

ElectronJS/main.js:1270 创建 WebSocket 服务时没有认证握手、没有校验 Origin、也没有指定监听 host

javascript
// main.js:1270
let wss = new WebSocket.Server({port: websocket_port});   // websocket_port = 8084 (main.js:57)
wss.on("connection", function (ws) {
    ws.on("message", async function (message, isBinary) {
        let msg = JSON.parse(message.toString());
        ...
    });
});
  • 未指定 host → 默认绑定 0.0.0.0(实测监听 *:8084),局域网内其他设备可访问
  • verifyClient / 无 Origin 校验 → 任何连接都被接受
  • 消息分发对"连接者身份"不加区分:任意连接者按合法流程图页面的协议(ElectronJS/src/taskGrid/logic.js:16-24)发送注册消息,即可被服务端视为可信页面。

完整调用链(源码级)

步骤 位置 行为
1 main.js:1270 无鉴权 WebSocket 服务监听 8084
2 main.js:1276-1288 if (msg.type == 0)msg.message.id == 2socket_flowchart = ws任意连接可注册自己
3 main.js:1123-1126 msg.type == 7driver.manage().getCookies() 读取当前浏览器全部 Cookie
4 main.js:1128-1133 拼装 name=value 文本,socket_flowchart.send(...) 回传给注册的连接者

合法客户端同款协议:src/taskGrid/logic.js:16-24(注册 {type:0,message:{id:2}})、src/taskGrid/FlowChart.js:286-293(触发 {type:7} 抓取 Cookie)。这是"在流程图画布上获取当前页面 Cookie"的正常功能,但服务端把该功能开放给了任意未授权连接

4. 威胁模型与前提条件

  • 前提 1:EasySpider 正在运行(Electron 主进程已启动,8084 服务在线)。
  • 前提 2:正在自动化的浏览器当前持有某些站点的 Cookie(用户通常用 EasySpider 采集"已登录"网站,此前提在典型使用中成立)。
  • 前提 3:攻击者能连到 8084。三种现实通道:
    1. 同局域网设备:端口绑定所有网卡,扫描到主机即可连接(无需经过互联网);
    2. 本机任意进程:本地程序直接连 ws://127.0.0.1:8084
    3. 本机恶意网页:服务端不校验 Origin,用户浏览器中任意页面可发起 ws://127.0.0.1:8084(浏览器 Private Network Access 仅对部分环境拦截)。
  • 攻击者不需要任何应用内认证,EasySpider 无用户登录系统,无身份门槛。

5. 影响

攻击者获得正在自动化浏览器中的全部第三方站点会话 Cookie。由于用户常用 EasySpider 采集已登录站点,这些 Cookie 通常包含有效登录态。后果:

  • 身份冒用:攻击者把 Cookie 导入自己的浏览器,即以受害者身份登录其账号,可读取/修改其数据、执行其权限内操作;
  • 泄露范围取决于受害者浏览器中已登录站点的敏感性(购物、邮箱、工作系统等);
  • 该未鉴权通道不限于 type==7:同一服务还承载任务执行、窗口控制等消息类型,存在更大的潜在攻击面(本次仅报告已证实的 Cookie 泄露)。

6. 动态验证(本机真实执行)

环境:macOS、真实 Google Chrome、selenium-webdriver + ws。服务器端为从 main.js:1270-1293、1123-1136 逐行原样搬移的处理逻辑;浏览器通过 Selenium 驱动真实 Chrome,并在 example.com 上设置两个合成演示 Cookiesessionid=SIMULATED-SESSION-0a1b2c3dauth_token=SIMULATED-TOKEN-7f6e5d4c),模拟受害者已登录的第三方会话。

正向验证(攻击成功):

[server] browser ready, synthetic cookies set on example.com
[server] WebSocket server listening on ws://0.0.0.0:8084 (unauthenticated)

[attacker] connected with no auth
[attacker] RECEIVED FROM SERVER:
{"type":"GetCookies","message":"auth_token=SIMULATED-TOKEN-7f6e5d4c\nsessionid=SIMULATED-SESSION-0a1b2c3d"}

服务端日志同时确认其通过 driver.manage().getCookies() 读到了浏览器 Cookie 并回传。

负向对照(不注册则拿不到数据):

[neg] connected (no auth, NO registration)
[neg] result: no data returned (expected)

说明:socket_flowchart 为 null 时 null.send() 抛错,被 try/catch 吞掉,攻击者收不到任何数据。这证明"能否拿到 Cookie"的唯一门槛就是注册步骤,而注册步骤本身不要求任何凭据

监听地址实测:

node  TCP  *:8084 (LISTEN)   # 所有网卡,非 127.0.0.1 → 局域网可达

复现步骤(对运行中的 EasySpider 同样适用):

  1. 启动 EasySpider,等待其自动打开浏览器(无需任何配置)。
  2. 从同网段另一台设备(或本机进程/脚本)连接 ws://<EasySpider主机IP>:8084
  3. 发送 {"type":0,"message":{"id":2}}
  4. 发送 {"type":7}
  5. 接收服务端回传的 GetCookies 消息,其中包含当前浏览器所有站点的 name=value Cookie。

验证范围说明:复现的是 main.js 中漏洞处理逻辑的逐字等价实现 + 真实 Chrome,未运行完整 Electron GUI;Cookie 使用合成值,未触碰任何真实用户数据,未对任何线上系统发起探测。

7. 与已公开问题(#466)的关系

作者曾在 #466(端口 8074 任意文件读取,Closed as not planned)回复:

"默认就是本地运行的软件不经过互联网……大型组织和公司……肯定会写或者集成到自己的带有鉴权的完善的认证系统,所以这个问题对于此项目来说可以忍受。"

本报告不是 #466 的重复,二者为不同漏洞、不同端口、不同攻击面(#466:HTTP 服务路径遍历读文件;本报告:无鉴权 WebSocket 窃取浏览器 Cookie)。且作者此前被告知的辩护理由对本案不成立

  1. "默认本地运行、不经互联网" —— 实测 8084 绑定所有网卡,同局域网设备可直接访问,无需经过互联网;
  2. 服务端不校验 Origin,本机浏览器中的恶意网页也可连接(用户自己成了攻击通道);
  3. 无 SECURITY.md、无私有报告流程指引之外的任何安全边界,海量普通桌面用户按默认配置运行,同样暴露。

8. 修复建议

  1. 握手鉴权:连接建立时要求携带主进程生成的一次性 token,仅可信的本地官方页面(流程图/扩展)能获取该 token。
  2. 校验 Origin:在 wss 握手阶段校验 Origin,只放行官方页面来源。
  3. 收敛监听地址:默认显式绑定 127.0.0.1;如确需局域网访问,必须叠加鉴权。
  4. 敏感操作权限化:对 type==7(Cookie 导出)、任务执行、窗口控制等敏感消息类型增加二次鉴权/会话绑定校验。
  5. 回归测试:新增"未携带 token / 非本地 Origin 的连接无法触发 Cookie 导出"的自动化用例。

9. 披露说明

  • 本报告基于 commit 191bd6d7(v0.6.3)源码分析与本机动态验证,遵循负责任披露流程;
  • 已核查仓库历史:无公开 issue 报告过本问题(#466/#504 为端口 8074 文件读取,#972 已由报告者撤回),去重结果 clear;
  • 已确认仓库启用 GitHub 私有漏洞报告(Security → "Report a vulnerability"),建议经此通道提交;
  • 本报告不含真实密钥、真实用户数据或可利用的完整攻击载荷。