这可能是一个特定的问题(研究项目),但我正在寻找一种好方法,使这个程序比现在更"安全".

目标是接受任意用户代码(在通过单元测试和手动判断之后),并将其合并到正在运行的程序中,而无需重新加载应用程序.

具体的例子是,它是一个持续执行的绘图应用程序,我希望学生/其他用户能够提交脚本(遵循特定的格式/指导原则).

我目前的实现是要求用户指定他们的类名与他们的文件名匹配(例如,myclass.js中有一个const myclass = class { ... }块).然后,当我看到我的服务器中存在一个新文件时(一个判断特定目录内容的FlaskTM应用程序),该JavaScript应用程序将加载该特定文件.

目前,我已经准备好了一个promise来确保加载脚本,但我要做的一般方法是将其放入内存:

function loadNewScript(scriptName) {
  let s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", `/static/techniques/${scriptName}`);
  let nodes = document.getElementsByTagName("*");
  let node = nodes[nodes.length - 1].parentNode;
  node.appendChild(s);
}

然而,我预料到的安全问题(而不是我认为的任意代码)是,我当前使用eval将类放入内存:

// technique comes in as 'myclass.js'
function loadObject(technique) {
    try {
        let obj = eval(technique.split(".")[0]);
        let _activeObj = new obj();
        if (typeof _activeObj != "undefined") {
            return _activeObj;
        }
        return null;
    } 
    catch (e) { // will check for syntax errors, but this usually trips when the script isn't loaded yet
        return null;
    }
}

目前这是可行的,但是我有点担心eval在这里的使用.我看到过关于使用windowthis命名空间的帖子,但据我所知,你不能将动态加载的脚本添加到全局命名空间中吗?无论如何,使用window['myclass']this['myclass']在加载后都不起作用.(How to execute a JavaScript function when I have its name as a string)

推荐答案

实际上,如果您已经将"任意的"(经过审核的)代码加载到动态<script>中,那么出于安全考虑而避免eval是没有意义的.window['myclass']不起作用的问题是因为const does declare a global variable but create a property of the global object.您需要将脚本更改为使用var myclass = class { ... };.

但是,我建议您更改您的实施,以要求文件遵循ES6模块格式:

export default class myclass { ... }

然后您可以使用以下命令加载这些文件

function loadNewScript(scriptName) {
    return import(`/static/techniques/${scriptName}`);
}
async function loadObject(technique) {
    const module = await loadNewScript(technique);
    const obj = module.default;
    return new obj();
}

如果您需要loadObject方法是同步的(而不是返回promise ),您可以使用use an object or Map as a class registry:

const registry = {};
async function loadNewScript(scriptName) {
    const module = await import(`/static/techniques/${scriptName}`);
    registry[scriptName] = module.default;
}
function loadObject(technique) {
    const obj = registry[technique];
    return obj ? new obj() : null;
}

Javascript相关问答推荐

如何解决chrome—extension代码中的错误,它会实时覆盖google—meet的面部图像?'

使搜索栏更改语言

Snowflake JavaScript存储过程返回成功,尽管预期失败

在网页上添加谷歌亵渎词

Chromium会将URL与JS一起传递到V8吗?

如何将react—flanet map添加到remixjs应用程序

Javascript json定制

如何在文本字段中输入变量?

try 使用javascript隐藏下拉 Select

React.Development.js和未捕获的ReferenceError:未定义useState

按下单键和多值

MongoDB受困于太多的数据

使用类型:assets资源 /资源&时,webpack的配置对象&无效

用于部分字符串的JavaScript数组搜索

P5play SecurityError:无法从';窗口';读取命名属性';Add';:阻止具有源的帧访问跨源帧

扩散运算符未按预期工作,引发语法错误

在使用JavaScript以HTML格式显示Google Drive中的图像时遇到问题

MAT-TREE更多文本边框对齐问题

使用onClick单击子元素时,使用交点观察器的关键帧动画意外运行

打字脚本中的函数包装键入