首页 > 解决方案 > 在我的游戏中安全运行用户编写的 Javascript

问题描述

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

我正在制作一个游戏,我打算写一个相当大的关卡编辑器。在我看来,这个关卡编辑器可能足够强大,足以让我编写整个游戏。这意味着,我只需向该游戏编辑器添加新功能即可为游戏添加功能。到目前为止,一切都很好。但是,我的游戏是用 Javascript 编写的,我计划在同一个游戏引擎中制作关卡编辑器,这样我就可以将它与游戏一起发布,让玩家制作自己的关卡。在那个关卡编辑器中,我计划添加脚本功能来扩展游戏的功能。

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

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

我希望他们能够访问我给他们的一些 JS 对象,而不是别的。我不希望他们能够访问任何其他变量,例如窗口、导航器、控制台等。我只希望他们能够访问我的游戏的运行时对象以及我提供给他们的任何实用程序函数。那么,我怎样才能安全地做到这一点呢?

标签: javascripthtmlsecurityxssgame-engine

解决方案


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

您可能可以做一些恶作剧,例如使用withandnew Function试图阻止用户访问某些全局属性,但这会很乏味,而且我没有信心能够成功。

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

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

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


推荐阅读