写点什么

我的 Electron 客户端被第三方页面入侵了

  • 2024-08-05
    湖南
  • 本文字数:1905 字

    阅读完需:约 6 分钟

问题描述

公司有个内部项目是用 Electron 来开发的,有个功能需要像浏览器一样加载第三方站点。


本来一切安好,但是某天打开某个站点的链接,导致 整个客户端直接变成了该站点的页面。


这一看就是该站点做了特殊的处理,经排查网页源码后,果然发现了有这么一句代码。

if (window.top !== window.self) {  window.top.location = window.location;}
复制代码

翻译一下就是:如果当前窗口不是顶级窗口的话,将当前窗口设置为顶级窗口。


奇怪的是两者不是 跨域 了吗,为什么 iframe 还可以影响顶级窗口。


先说一下我当时的一些解决办法:

  1. 用 webview 替换 iframe

  2. 给 iframe 添加 sandbox 属性


后续内容就是一点复盘工作。

场景复现(Web 端)

一开始怀疑是客户端的问题,所以我用在纯 Web 上进行了一次对比验证。


这里我们新建两个文件:1.html 和 2.html,我们称之为 页面 A 和 页面 B。


然后起了两个本地服务器来模拟同源与跨域的情况。

  • 页面 A:http://127.0.0.1:5500/1.html

  • 页面 B:http://127.0.0.1:5500/2.html 和 http://localhost:3000/2.html

符合同源策略

<body>  <h1>这是页面A</h1>  <!-- 这是同源的情况 -->  <iframe id="iframe" src="http://127.0.0.1:5500/2.html" />    <script>    iframe.onload = () => {      console.log('iframe loaded..')      console.log('子窗口路径', iframe.contentWindow.location.href)    }  </script></body>
复制代码


<body>  <h2>这是页面B</h2>
<script> console.log('page2...') console.log(window === window.top) console.log('顶部窗口路径', window.top.location.href) </script></body>
复制代码

我们打开控制台可以看到 页面 A 和 页面 B 是可以 互相访问 到对方窗口的路径。

如果这个时候在 页面 B 加上文章开头提到的 代码片段,那么显然页面将会发生变化。

跨域的情况

这时候我们修改 页面 A 加载 页面 B 的地址,使其不符合同源策略。

理所应当的是,两个页面不能够相互访问了,这才是正常的,否则内嵌第三方页面可以互相修改,那就太不安全了。

场景复现(客户端)

既然 Web 端是符合预期的,那是不是 Electron 自己的问题呢?


我们通过 electron-vite 快速搭建了一个 React 模板的 electron 应用,版本为:electron@22.3.27,并且在 App 中也嵌入了刚才的 页面 B。

function App(): JSX.Element {  return (    <>      <h1>这是Electron页面</h1>      <iframe id="iframe" src="http://localhost:3000/2.html"/>    </>  )}export default App
复制代码


对不起,干干净净的 Electron 根本不背这个锅,在它身上的表现如同 Web 端 一样,也受同源策略的限制。


那么肯定是我的项目里有什么特殊的配置,通过对比主进程的代码,答案终于揭晓。

new BrowserWindow({    ...,    webPreferences: {        ...,        webSecurity: false // 就是因为它    }})
复制代码

Electron 官方文档 里是这么描述 webSecurity 这个配置的。


webSecurity boolean (可选) - 当设置为 false, 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的,还会把 allowRunningInsecureContent 设置为 true. 默认值为 true。


也就是说,Electron 本身是有一层屏障的,但当该属性设置为 false 的时候,我们的客户端将会绕过同源策略的限制,这层屏障也就消失了,因此 iframe 的行为表现得像是嵌套了同源的站点一样。

解决方案

把这个配置去掉,确实是可以解决这个问题,但考虑到可能对其他功能造成的影响,只能采取其他方案。


如文章开头提到的,用 webview 替换 iframe。


webview 是 Electron 的一个自定义元素(标签),可用于在应用程序中嵌入第三方网页,它默认开启安全策略,直接实现了主应用与嵌入页面的隔离。


因为目前这个需求是仅作展示,不需要与嵌套页面进行交互以及复杂的通信,因此在一开始的开发过程中,并没有使用它,而是直接采用了 iframe。


而 iframe 也能够实现类似的效果,只需要添加一个 sandbox 属性可以解决。


MDN 中提到,sandbox 控制应用于嵌入在 <iframe> 中的内容的限制。该属性的值可以为空以应用所有限制,也可以为空格分隔的标记以解除特定的限制。


如此一来,就算是同源的,两者也不会互相干扰。

总结

这不是一个复杂的问题,发现后及时修复了,并没有造成很大的影响(还好是自己人用的平台)。


写这篇文章的主要目的是为了记录这次事件,让我意识到在平时开发过程中,把注意力过多的放在了 业务、样式、性能等这些看得见的问题上,可能很少关注甚至忽略了 安全 这一要素,以为前端框架能够防御像 XSS 这样的攻击就能安枕无忧。


谨记,永远不要相信第三方,距离产生美。


如有纰漏,欢迎在评论区指出。


作者:小陈同学吗

链接:https://juejin.cn/post/7398418805971877914

用户头像

欢迎关注,一起学习,一起交流,一起进步 2020-06-14 加入

公众号:做梦都在改BUG

评论

发布
暂无评论
我的 Electron 客户端被第三方页面入侵了_黑客_我再BUG界嘎嘎乱杀_InfoQ写作社区