New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

safe-load-script

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

safe-load-script

Dynamically load script and can be safely executed

latest
Source
npmnpm
Version
0.0.1
Version published
Maintainers
1
Created
Source

safe-load-script

动态加载 JS 脚本,几乎 100% 安全执行。

English

安全性实现原理

目前社区针对第三方 JS 的不受信执行,基本都是采用拦截或者代理的方式,但这种方式并不安全。例如虽然拦截了 window 全局变量,还能操作 DOM,还能修改内置对象的原型链,总之这种方式是防君子,难防小人。

但浏览器本身就有一个完美的沙箱,即 iframe。我们通过动态创建一个 iframe,并将 JS 放到 iframe 中执行,然后将执行结果(挂载到 window 的变量),返回给主应用,最后将 iframe 删除,就几乎完美的达到了沙箱的能力。

这里之所以说几乎,是因为我们有时还需要注入一些第三方 JS 的依赖变量,例如我们需要给第三方 React 组件注入 React、ReactDOM,这些仍然有可乘之机。

Feature

  • JS 运行在 iframe 中运行,几乎 100% 安全执行。
  • 支持内联代码块和外部链接。
  • 支持 UMD 模块

Installation

yarn add safe-load-script # or npm install safe-load-script -S

Example Usage

加载一个 umd 模块链接示例。

import { safeLoadScript } from "safeLoadScript";

async function main() {
  const React = await safeLoadScript({
    url: "https://unpkg.com/react/umd/react.production.min.js",
    umd: true, // 上面的链接实际是一个 UMD 格式模块
  });
}

main();

PS:UMD 加载和非 UMD 加载区别其实很简单,我们以上面为例,这个连接最终会在 window 上挂一个 React 全局变量,如果是 umd 为 true 的情况下,返回的就是 React 对象,如果为 false 或者不填,则返回的是 { React } 对象。

执行内联 JS 代码示例。

import { safeEvalCode } from "safeEvalCode";

const { foo, bar } = await safeEvalCode({
  code: `
    window.foo = 'foo';
    window.bar = 'bar';
  `,
});
console.log(foo, bar);

在加载一些链接时,需要注入相应的依赖,例如 UMD 的 React 组件是依赖 React、ReactDOM。想要做到这个能力有两种方式:

  • autoRejectAllGlobalProperties 自动注入
  • injectGlobalProperties 手动注入
import React from "react";
import ReactDOM from "react-dom/client";
import { safeLoadScript } from "safeLoadScript";

// 自动注入的方式
window.React = React;
window.ReactDOM = ReactDOM;

const antd = await safeLoadScript({
  url: "https://unpkg.com/browse/antd/dist/antd.min.js",
  umd: true,
  autoRejectAllGlobalProperties: true, // 自动注入
});
import React from "react";
import ReactDOM from "react-dom/client";
import { safeLoadScript } from "safeLoadScript";

window.React = React;
window.ReactDOM = ReactDOM;

const antd = await safeLoadScript({
  url: "https://unpkg.com/browse/antd/dist/antd.min.js",
  umd: true,
  injectGlobalProperties: {
    // 手动注入
    React,
    ReactDOM,
  },
});

某些场景下并不是立即挂载到全局变量上,此时我们可以使用回调函数的形式获取值。

import { safeEvalCode } from "safeEvalCode";

safeEvalCode({
  code: `
    // 代码执行完了,但是异步函数里做了操作
    setTimeout(() => {
      window.foo = 'foo';
    }, 1000)
  `,
  successCallack({ foo }) {
    console.log(foo);
  },
});

如果我们想要一直监听 JS 里面的执行,而不是执行完就销毁,我们可以在 successCallback 返回 true 即可。

API

interface Options {
  // 链接
  url: string;
  // 是否以 umd 的方式获取结果
  umd?: boolean;
  // 唯一标识,用于复用 iframe
  name?: string;
  // 自定义处理 iframe
  processIframe?: (iframe: HTMLIFrameElement) => void;
  // 成功回调,当返回为 `true` 时,继续监听
  successCallack?: (newProperties: Record<string, any>) => boolean | void;
  // 错误回调
  errorCallback?: (error: Error) => void;
  // 是否在执行后立即销毁 iframe
  destoryIframeAfterEval?: boolean;
  // 是否自动注入主应用的所有的全局变量
  autoRejectAllGlobalProperties?: boolean;
  // 指定注入的全局变量
  injectGlobalProperties?: Record<string, any>
}

Keywords

umd

FAQs

Package last updated on 21 Aug 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts