如何在Chrome扩展中读取网页接收的WebSocket消息
Chrome扩展获取目标站点WebSocket消息的实现方案
核心实现路径
1. 页面脚本Hook捕获(侵入式)
这种方案是最早实现、兼容性最高的方式,核心逻辑是改写页面运行环境的原生WebSocket实现,在消息收发环节插入捕获逻辑。
- 必须满足两个前置条件才能生效:
- 注入时机设置为早于目标站点业务脚本执行:在manifest中配置内容脚本的
run_at为document_start,避免错过网站初始化阶段建立的WebSocket连接。 - 注入目标选择页面主世界:Chrome扩展的默认内容脚本运行在隔离世界,和页面自身的脚本环境完全隔离,直接在隔离世界改写WebSocket构造函数无法影响页面实际使用的实例,必须将hook脚本注入到页面的MAIN世界才能生效。
- 注入时机设置为早于目标站点业务脚本执行:在manifest中配置内容脚本的
- 跨环境通信逻辑:主世界捕获到消息后,通过
window.postMessage将数据传递给同标签页的内容脚本,再由内容脚本通过chrome.runtime.sendMessage转发到扩展后台服务处理。 - 参考hook实现代码:
// 注入主世界、document_start阶段执行 const NativeWebSocket = window.WebSocket; window.WebSocket = function(...params) { const ws = new NativeWebSocket(...params); // 捕获服务端推送的入站消息 ws.addEventListener('message', (evt) => { window.postMessage({ hookTag: '__ws_capture_v1__', direction: 'incoming', payload: evt.data }, '*'); }); // 可选:捕获页面主动发送的出站消息 const nativeSend = ws.send.bind(ws); ws.send = (data) => { window.postMessage({ hookTag: '__ws_capture_v1__', direction: 'outgoing', payload: data }, '*'); return nativeSend(data); }; return ws; }
2. 原生WebRequest API捕获(非侵入式)
这种方案完全不修改页面的运行逻辑,通过Chrome扩展提供的网络层API直接获取WebSocket传输内容,稳定性更高,不会触发站点的CSP策略、脚本完整性校验拦截。
- 依赖的专属事件接口:
chrome.webRequest.onWebSocketCreated:获取WebSocket连接创建的基本信息chrome.webRequest.onWebSocketFrameReceived:捕获服务端推送到页面的WebSocket帧内容chrome.webRequest.onWebSocketFrameSent:捕获页面发到服务端的WebSocket帧内容
- 权限要求:需要在manifest中声明
"webRequest"权限,以及目标站点的host权限,无需开发者模式或者特殊调试权限,适配正式上架的扩展场景。 - 局限性:网络层拿到的是传输层的原始WebSocket帧,如果目标站点对消息做了自定义二进制编码、分片封装,需要自行匹配站点的协议规则做解码,无法直接拿到业务层的结构化消息内容。
常见踩坑提醒
- 不要尝试从页面全局变量中遍历获取已存在的WebSocket实例:大多数站点会把WebSocket实例存在闭包作用域内,不会暴露到全局环境,扩展的隔离环境无法访问这类闭包引用,自然读不到对应的消息。
- 跨环境消息必须做来源校验:内容脚本监听
message事件时,需要校验消息内的自定义hook标识,过滤掉页面其他脚本伪造的消息,避免逻辑异常。 - 侵入式hook方案需要注意站点的CSP策略限制:如果站点配置了严格的脚本加载规则,可能会拦截注入的主世界脚本,此时需要优先选择非侵入式的WebRequest方案。
- 不建议正式版本使用DevTools协议方案:这类方案需要扩展申请调试权限,安装时会触发强安全提示,且部分企业环境会禁用对应能力,仅适合开发阶段调试使用。
内容的提问来源于stack exchange,提问作者Eric Hong
相关产品推荐
相关产品推荐

