乐趣区

关于前端:奇技淫巧话前端使用-iframe-实现与父页面跨域隔离的-JavaScript-代码沙箱

如果让你实现一个在线的 JavaScript 代码运行环境,要求用户代码不能对页面进行批改,以防止潜在的平安问题,你会怎么做?
应用 with?应用 proxy?OK,都能够,然而这两种办法都须要关注很多细节,否则用户仍旧有可乘之机,这样一来你的实现外面就会有一个很长长长长长长长的操作黑名单。
除此之外,咱们还能够专门部署一个页面,将代码提到服务端渲染成页面,再通过 iframe 去拜访,如果 iframe 与父页面之间是跨域的话能够达到很高的安全性——那么能不能不看后端的脸色,齐全应用浏览器来实现相似的沙箱呢?
当然能够——

1. iframe

对前端页面而言,跨域是页面与页面之间的鸿沟,但这并不意味着咱们必须从新关上一个页面来运行新的代码,因为咱们能够应用 <iframe> 标签:

<iframe src="www.xxxx.xxx"></iframe>

对于同域的 iframe,咱们能够间接通过 .contentWindow 拜访并操作它的全局对象,而后间接往里面执行 JavaScript:

document.querySelector('iframe')
  .contentWindow
  .eval('alert("hello world!");');

然而同域页面的子页面是能够与父页面进行互操作的,

2. data URL

你可能在一些页面里见过小图片不应用网络链接,而是采纳一个 data:image/png;base64 xxxxxxx 格调的 URL,这种 URL 就是 data URL。

除了 data URL 之外你可能还见过 blob:// 结尾的 URL —— Object URL。不过 Object URL 与以后页面是同域的,而 data URL 与以后页面是跨域的。所以 咱们能够在 iframe 应用 data URL 来进行跨域隔离

3. 将 JavaScript 代码变成 data URL

咱们能够间接将 JavaScript 片段变成 data:application/javascript, 的 URL,然而这样有一个问题:iframe 关上这样的 URL 的时候,会显示代码原文而不是执行代码,这个行为其实和你间接在浏览器地址栏输出 JS 的 URL 是一样的。
所以咱们须要将 JavaScript 代码拼接到 html 外面,再变成 data URL,而后交给 iframe 去加载:


const javaScriptFragment = `
alert('hello world');
`;

const htmlFragment = `
<!doctype html>
<html>
  <head>
    <meta chatset="utf-8" />
  </head>
  <body>
    <script>${javaScriptFragment}</script>
  </body>
</html>
`;

const dataUrl = `data:text/html,${htmlFragment}`;
// 留神,如果代码片段中含有中文的话,须要应用 encodeURIFragment 本义 htmlFragment

document.querySelector('iframe').src = dataUrl;

4. 如果须要获取执行后果的话,基于 postMessage 定制通信机制

如果咱们岂但要做沙箱隔离,还被要求获取运行后果的话,则能够做一个通信机制,让 iframe 获取到用户代码执行后果,iframe 与父页面之间最好的跨域通信办法莫过于 postMessage
除了获取后果之外,还能够将通信机制进一步扩大成为 RPC,这样能够实时批改页面里的代码来查看成果,相似于 codepen。
具体实现与主题不是强相干,这里就不写了。

退出移动版