在我的游戏中安全运行用户编写的Javascript



我有一个棘手的问题需要解决,我做了很多研究,但我认为我还没有找到完美的答案。

我正在制作一个游戏,我计划写一个相当大的级别编辑器。在我看来,这个关卡编辑器可能足够强大,可以让我在里面编写整个游戏。这意味着,我只需要在游戏编辑器中添加新功能就可以为游戏添加功能。到目前为止,一切都很好。然而,我的游戏是用Javascript编写的,我计划在同一个游戏引擎中制作关卡编辑器,这样我就可以在游戏中附带它,让玩家制作自己的关卡。在这个级别编辑器中,我计划添加脚本功能来扩展游戏的功能。

这意味着,我希望级别编辑器能够运行Javascript。所以我希望用户能够在游戏中编写和运行JS,也能够分享他们的关卡,让其他人玩这些关卡。

现在,这听起来真的很糟糕。这是我基本上允许用户通过我的游戏进行XSS。我想了很多方法,基本上,我还没有找到任何允许用户安全地完成这项工作的解决方案。

我希望他们能够访问我给他们的一些JS对象,而不访问其他任何对象。我不希望他们能够访问任何其他变量,如窗口、导航器、控制台等。那么,我怎样才能安全地完成呢?

如果自定义脚本在客户端上运行,第一步至少是在沙盒中运行,而不是在父页面上运行。您可以从用户提供的脚本创建一个web工作程序,然后向该工作程序传递一条消息,其中只包含您希望它能够使用的信息。工作程序在单独的环境中运行,不提供对原始页面的访问,也不提供对许多内置浏览器对象的访问。但是一些内置对象仍然可以访问,比如window.consolewindow.fetch。如果这是可以接受的,您可以在worker中运行用户的脚本,并让它将消息发布回原始页面,然后丢弃worker。

你可能会做一些恶作剧,比如使用withnew Function来阻止用户访问某些全局属性,但这会很乏味,我对成功做到这一点没有信心。

更好的方法是在真正隔离的世界中运行脚本-将代码发送到服务器,然后使用Node使用vm.runInNewContext运行脚本,并让服务器将结果发送回客户端。这提供了您需要的隔离,因为:

当您使用此函数时,它会创建一个非常有限的上下文。您需要将您想要的任何东西传递到沙箱对象中,沙箱对象将成为全局对象。例如:如果您希望不受信任的代码写入控制台,则需要在沙盒对象中包含控制台。

也就是说,在大多数情况下,我首先会考虑运行用户的JS是否绝对必要。我更喜欢允许用户通过定义他们输入文本的文本格式来自定义行为。但是,如果你需要在游戏中提供无限的灵活性,那么如果游戏很复杂,创建这样一种(本质上(编程语言可能会非常耗时。

最新更新