如何在Chrome扩展中记录网站自动建立的WebSocket服务端请求?
如何在Chrome扩展中劫持并记录网站原有WebSocket的消息
为什么window.WebSocket会返回undefined?
Chrome扩展的内容脚本默认运行在隔离世界中,这个环境和页面自身的全局环境完全分开——你在内容脚本里访问的window并不是页面实际的window对象,所以拿不到页面的WebSocket构造函数,自然返回undefined。解决核心是把劫持代码注入到页面的主世界(页面自身的全局上下文)里。
实现WebSocket消息记录的具体方案
1. 编写劫持脚本
下面的代码会重写页面的WebSocket构造函数,在不破坏原有功能的前提下,记录所有新建立的WebSocket连接和收到的消息:
(function() { // 保存原始的WebSocket构造函数 const OriginalWebSocket = window.WebSocket; // 重写WebSocket构造函数 window.WebSocket = function(...args) { // 创建原始的WebSocket实例 const wsInstance = new OriginalWebSocket(...args); // 记录连接建立的信息(比如连接地址) console.log('[WS Logger] 新连接建立:', args[0]); // 处理onmessage事件 const originalOnMessage = wsInstance.onmessage; wsInstance.onmessage = function(event) { try { // 解析并记录消息内容 const messageData = JSON.parse(event.data); console.log('[WS Logger] 收到消息:', messageData); } catch (e) { // 如果消息不是JSON格式,直接打印原始数据 console.log('[WS Logger] 收到非JSON消息:', event.data); } // 调用原本的onmessage逻辑,保证页面功能正常 if (originalOnMessage) originalOnMessage.call(this, event); }; // 处理通过addEventListener绑定的message事件 const originalAddEventListener = wsInstance.addEventListener; wsInstance.addEventListener = function(type, listener, options) { if (type === 'message') { const wrappedListener = function(event) { try { const messageData = JSON.parse(event.data); console.log('[WS Logger] 收到消息(listener):', messageData); } catch (e) { console.log('[WS Logger] 收到非JSON消息(listener):', event.data); } // 调用原本的监听函数 listener.call(this, event); }; return originalAddEventListener.call(this, type, wrappedListener, options); } return originalAddEventListener.call(this, type, listener, options); }; return wsInstance; }; // 复制原始WebSocket的静态属性(比如WebSocket.CLOSED等常量) Object.assign(window.WebSocket, OriginalWebSocket); })();
2. 在扩展中注入脚本
有两种方式可以把上述代码注入到页面主世界:
- 方式一:Manifest配置(Chrome 112+)
在manifest.json中添加内容脚本配置,指定world: "MAIN"直接注入到主世界:{ "manifest_version": 3, "name": "WebSocket Logger", "version": "1.0", "content_scripts": [ { "matches": ["https://your-target-site.com/*"], // 替换成你的目标网站 "js": ["ws-logger.js"], // 把上面的代码保存为ws-logger.js "world": "MAIN", "run_at": "document_start" // 确保在页面加载前注入 } ] } - 方式二:动态注入(兼容旧版本Chrome)
如果需要兼容Chrome 112以下版本,可以在内容脚本中动态创建<script>标签注入代码:
同时在// content-script.js const injectScript = document.createElement('script'); injectScript.textContent = ` // 把上面的劫持代码粘贴到这里 (function() { const OriginalWebSocket = window.WebSocket; // ... 完整劫持逻辑 })(); `; // 注入到页面并立即移除标签 document.documentElement.appendChild(injectScript); injectScript.remove();manifest.json中配置这个内容脚本在document_start时运行:{ "content_scripts": [ { "matches": ["https://your-target-site.com/*"], "js": ["content-script.js"], "run_at": "document_start" } ] }
能否直接在控制台测试?
可以,但有个关键前提:必须在页面加载前注入代码,否则页面已经建立的WebSocket连接不会被劫持。具体操作:
- 打开目标网站的控制台(F12)
- 在控制台中粘贴上述劫持代码并执行
- 刷新页面——此时页面新建立的WebSocket连接就会被记录
如果页面已经加载完成再粘贴代码,只能记录之后新建的连接,之前已经存在的连接无法被捕获。
内容的提问来源于stack exchange,提问作者Brage
相关产品推荐
相关产品推荐

