如何修复SonarQube检测到的跨域通信消息来源未验证漏洞
漏洞潜在成因
这是前端postMessage跨源通信场景下的经典未授权访问风险,触发原因非常明确:
- 你的代码直接给全局上下文绑定了
message事件监听,处理消息前完全没有校验消息发送方的来源。因为你的应用以iframe形式运行,任何第三方站点都可以嵌入你的iframe,并且向它发送任意构造的消息。 - 目前你的消息处理逻辑可以直接控制计时器的初始化和重置,攻击者只要在自己的恶意页面里嵌入你的iframe,就能随意发送
init、resetTimer指令打乱你的业务逻辑;如果后续你在这个监听函数里加了用户身份读取、敏感数据上报、DOM操作之类的逻辑,还可能进一步导致数据泄露、XSS等更严重的安全问题。 - SonarQube的这条规则本质是强制做左移安全校验:只要代码里存在
message事件监听,且处理消息前没有对e.origin做可信校验,就会报出这个漏洞。
修复方案
修复的核心原则是:永远不要信任未校验来源的跨源消息,具体落地步骤如下:
- 提前配置可信父页面来源的白名单,只处理你业务认可的域名发来的消息
- 所有消息处理逻辑必须放在来源校验之后执行,非可信源的消息直接丢弃不做任何响应
- 额外补充消息数据格式、参数类型的校验,避免非法入参导致逻辑异常
- 回发消息时明确指定目标源,不要用通配符
*导致消息泄露
修复后的参考代码如下:
// 替换为你业务实际允许嵌入iframe的父页面域名,不要加多余路径、宽松通配符 const TRUSTED_ORIGINS = new Set([ "https://www.your-main-site.com", "https://biz.your-main-site.com" ]); self.addEventListener("message", function(e) { // 来源校验放最前面,非可信源直接拦截 if (!TRUSTED_ORIGINS.has(e.origin)) { return; } // 基础格式校验,避免非法结构数据触发报错 if (!e.data || typeof e.data.cmd !== "string") { return; } switch (e.data.cmd) { case "init": // 单独校验参数合法性 if (typeof e.data.timeIntervalInSec !== "number" || e.data.timeIntervalInSec <= 0) { return; } _initializeTimer(e.data.timeIntervalInSec); break; case "resetTimer": clearTimeout(self.sessionTimer); if (typeof e.data.timeIntervalInSec !== "number" || e.data.timeIntervalInSec <= 0) { return; } _initializeTimer(e.data.timeIntervalInSec); break; default: // 回传消息时第二个参数明确传校验通过的e.origin,禁止传"*" self.postMessage({ status: "error", info: "please send a valid command" }, e.origin); break; } });
修复注意事项
- 不要为了省事写放行所有源的逻辑(比如直接注释校验、判断
e.origin存在就放行),也不要用正则匹配来源时写得过于宽松(比如匹配到包含你的域名字符串就放行,很容易被https://your-main-site.evil.com这类恶意域名绕过)。 - 如果你的业务确实需要被任意域名嵌入,必须保证
message监听里的所有逻辑都是无敏感权限的,同时对所有入参做严格的转义和校验,绝对不能在里面执行eval、操作DOM写入HTML、读写本地敏感存储之类的高危操作。
内容的提问来源于stack exchange,提问作者Geo Joseph
相关产品推荐
相关产品推荐

