You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular/JavaScript:替代eval的高效安全自定义脚本执行方案问询

更安全高效的自定义脚本执行方案替代eval

针对你当前用eval执行管理员自定义脚本的场景,以下是几个更安全、可控的替代方案,均支持异步逻辑:

一、用Function构造函数替代eval(提升作用域隔离)

Function比eval更可控,能明确限定脚本可访问的变量,避免意外泄漏全局对象。同时保留异步支持:

async runScript(script: string) {
  // 预定义允许脚本调用的方法,绑定当前上下文
  const allowedMethods = {
    updateForm: this.updateForm.bind(this),
    getForm: this.getForm.bind(this),
    alert: window.alert
  };

  if (!this.validateScript(script)) {
    alert("Script not safe");
    return;
  }

  try {
    // 创建异步函数,仅传入允许的方法作为参数,严格限制作用域
    const asyncScriptFn = new Function(
      ...Object.keys(allowedMethods),
      `return (async () => { ${script} })();`
    );
    return await asyncScriptFn(...Object.values(allowedMethods));
  } catch (e) {
    if (e instanceof SyntaxError) {
      alert(e.message);
    } else {
      console.error('Script execution error:', e);
      alert("Error in script");
    }
  }
}

二、AST白名单校验(替代黑名单,彻底避免绕过)

黑名单校验极易被绕过(比如用字符串拼接windo['w']+'indow'、Unicode转义等),改用AST(抽象语法树)解析脚本,遍历节点做白名单校验,能精确控制允许的语法和变量:

先引入AST解析库(比如acorn),然后实现校验逻辑:

import * as acorn from 'acorn';
import { walk } from 'acorn-walk';

validateScript(script: string): boolean {
  try {
    const ast = acorn.parse(script, { ecmaVersion: 'latest', allowAwaitOutsideFunction: false });
    let isValid = true;

    // 遍历AST节点,只允许预定义的语法和变量
    walk.simple(ast, {
      // 仅允许访问指定的方法和关键字
      Identifier(node) {
        const allowedNames = ['updateForm', 'getForm', 'alert', 'await', 'async', 'var', 'let', 'const'];
        if (!allowedNames.includes(node.name) && !/^\d+$/.test(node.name)) {
          isValid = false;
        }
      },
      // 禁止new操作符
      NewExpression() { isValid = false; },
      // 禁止eval调用
      CallExpression(node) {
        if (node.callee.type === 'Identifier' && node.callee.name === 'eval') {
          isValid = false;
        }
      },
      // 禁止访问window、document等全局对象
      MemberExpression(node) {
        if (node.object.type === 'Identifier' && ['window', 'document', 'require', 'fetch'].includes(node.object.name)) {
          isValid = false;
        }
      }
    });

    return isValid;
  } catch (e) {
    // 语法解析失败,直接判定为不安全
    return false;
  }
}

三、Web Worker隔离执行(最高级别的前端沙箱)

Web Worker拥有独立的全局环境,无法访问主线程的DOM和window对象,即使脚本存在恶意代码,也无法影响主线程。通过postMessage实现跨线程通信,执行允许的操作:

Worker脚本(worker.ts)

self.onmessage = async (e) => {
  const { script, formData } = e.data;

  // 定义允许的方法,通过postMessage与主线程交互
  const updateForm = (id: string, value: any) => {
    self.postMessage({ type: 'updateForm', id, value });
    return Promise.resolve();
  };
  const getForm = (id: string) => Promise.resolve(formData[id]);

  try {
    const asyncFn = new Function('updateForm', 'getForm', `
      return (async () => { ${script} })();
    `);
    await asyncFn(updateForm, getForm);
    self.postMessage({ type: 'success' });
  } catch (e) {
    self.postMessage({ type: 'error', message: (e as Error).message });
  }
};

主线程调用逻辑

async runScript(script: string) {
  if (!this.validateScript(script)) {
    alert("Script not safe");
    return;
  }

  return new Promise((resolve, reject) => {
    const worker = new Worker('./worker.ts');
    
    worker.onmessage = (e) => {
      switch (e.data.type) {
        case 'success':
          resolve(true);
          break;
        case 'updateForm':
          this.updateForm(e.data.id, e.data.value);
          break;
        case 'error':
          alert(e.data.message);
          reject(e.data.message);
          break;
      }
      worker.terminate();
    };

    // 传递脚本和必要的表单数据给Worker
    worker.postMessage({
      script,
      formData: this.currentFormData
    });
  });
}

方案对比

方案安全等级实现复杂度适用场景
Function构造函数中低快速替换eval,依赖校验严谨性
AST白名单校验高中需要精确控制脚本语法的场景
Web Worker隔离极高中对安全性要求极高的生产环境

额外安全建议

  • 仅开放给管理员级别的用户编写脚本,严格控制权限;
  • 记录所有脚本的执行日志(内容、时间、执行者),便于事后审计;
  • 给脚本执行设置超时时间,避免无限循环或耗时操作阻塞应用。

内容的提问来源于stack exchange,提问作者Ka Tech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:15:22