代码之家  ›  专栏  ›  技术社区  ›  Ka Tech

Angular/Javascript-自定义用户脚本(Eval)

  •  0
  • Ka Tech  · 技术社区  · 3 年前

    嗨,我们正在构建一个网络应用程序平台,用户可以使用拖放功能制作自己的智能表单。我们正在为管理员用户寻找一种方法,让他们创建自己的自定义脚本,使用应用程序的预定义功能运行一些逻辑。目前,我们提出的解决方案是使用eval()。

    知道Eval是“邪恶的”,我们已经实现了一个函数,在执行脚本之前检查脚本是否安全。从本质上讲,它将代码分解为令牌,然后根据黑名单运行这些令牌。诸如new、eval、window、require、fetch之类的东西,浏览器将显示错误。此外,该函数是通过角度服务执行的,因此我们试图限制注入的内容。

    下面是基本的高级代码。我们有自定义的异步函数,所以解决方案需要处理这个问题。

    我的问题是有更好(更快)更安全的方式来运行自定义脚本吗?

    async runScript(script,callback) {
     var updateForm=(id,value)=>{
       return this.updateForm(id,value);
     }
     var getForm=(id)=>{
       return this.getForm(id);
     }
     if (this.checkScriptSafe(script)) {       
           try {
              return eval("(async () => {" + script + "})()"); 
            } catch (e) {
                if (e instanceof SyntaxError) {
                    alert(e.message);
                } else {
                  console.log('Error',e);
                  alert("Error in script");
                }
            }
      } else { 
        alert("Script not safe")
       }
    }
    

    脚本示例:

    "var value = 1 +4; await updateForm("11",value);alert("Success!");"
    
    0 回复  |  直到 3 年前
        1
  •  1
  •   Mehmet Baker    3 年前

    Function constructor 这将是一个更好的方法。函数构造函数创建一个将在全局范围内执行的新函数。您的eval脚本(由于箭头函数)将在与您的 runScript 方法它们会访问/修改您的内部,或者覆盖您的类方法。他们甚至可以覆盖 运行脚本 方法本身并删除 checkScriptSafe 检查

    使用函数构造函数类似于在开发工具控制台中键入。如果您的应用程序不易受到开发工具控制台的攻击,那么使用函数构造函数就不会有任何问题。

    以下是一个示例:

    const script = `
      var value = 1 +4;\n
      await updateForm("11",value);\n
      alert("Success!");
    `;
    
    // we have to get a handle of the async function constructor
    // in order to create an async function
    const dummyFunction = async function() {}
    const AsyncFunction = dummyFunction.constructor;
    
    // create an async function which will run in the global scope
    // the function will have an `updateForm` parameter
    const userFunction = new AsyncFunction('updateForm', script);
    
    // now userFunction is equavalent of:
    // const userFunction = async function(updateForm) {
    //   var value = 1 +4;
    //   await updateForm("11",value);
    //   alert("Success!");
    // }
    
    // bind the current context 'this' to update form and pass it
    // to user's function as parameter. The user's function
    // will be able to execute it.
    userFunction(this.updateForm.bind(this));
    

    我不是浏览器内部的专家。但我认为,单独标记和解释函数会比函数构造函数方法慢得多。即使你以最有效的方式做每件事,你仍然会在JavaScript领域;v8(或任何其他JS引擎)将在您之后执行实际解释。为什么不直接把脚本交给JS引擎呢?如果相同的自定义脚本将频繁运行,那么通过正确的设计,v8将通过 compiling them into machine code eval

    推荐文章