适合在沙盒中运行客户端代码的语言

Suitable language for running client code in sandbox

本文关键字:客户端 代码 语言 运行      更新时间:2023-09-26

我想在我的服务器上模拟(不安全的)客户端代码,我正在寻找一种合适的语言来做到这一点。我更喜欢让客户端用我将用于模拟的相同语言编写。

  • 安全是首要问题
  • 最好是一门知名的语言(便于客户学习语法)
  • 应该很容易禁用/启用沙箱中可用的语言特性
  • 如果我能一步一步地模拟代码,
  • 将是一个加分项

理想情况下,我会简单地构造几个接口(并发布这些接口),加载客户端代码,并通过允许它只使用我的接口+我精心选择的标准API的子集来模拟该代码。

在这个模拟过程中,我应该能够限制客户端代码使用的资源(时间和内存)。如果我可以一步一步地模拟代码,那么我就可以总是返回一个确定性的解决方案。

性能不是真正的问题。其理念是允许客户为小型游戏/谜题编写自定义AI。游戏将被模拟(在服务器上!)并将结果返回给用户。

最初我想构造一个外部DSL自己,包括一个解析器和求值器,但也许有一个现成的解决方案在那里?

我的选择是使用一些脚本语言,这些脚本语言可以在不自动提供对某些扩展框架(如。net或Java)的访问的情况下使用——添加特性比限制它们更容易。像LUA这样的游戏引擎脚本语言可能是一种选择,并且通常带有用于多个平台的实现。

一般考虑:

无论你选择什么语言/框架,确保你可以从/接受风险中恢复过来:

  • 致命异常(如递归函数导致的堆栈溢出)
  • 无限内存分配/内存不足异常
  • 长时间运行任务

小心暴露那些允许用户在你的控制之外创建新线程/任务/同步对象(锁/信号量)的API,或者在提供此类API的平台上构建API。允许这样的方法可能会打开你的服务器的资源无限消耗或DOS/死锁…

注意,长时间运行的任务对于任何合理的语言来说都是一个问题,因为你不能通过查看它来确定程序是否结束——停止问题。不管你选择什么平台,你都必须想出一个解决方案。

。Net/C #:

你可以看看Terrarium,它在。net中就是这样做的——在沙箱环境中在用户的机器上运行不受信任的代码。

。Net提供了一种限制使用多个api的方法——如何:在沙盒中运行部分受信任的代码是一个很好的起点。请注意,正如@Andrew指出的那样,除了基本的沙箱之外,验证用户提供的程序集(无论是直接提供还是从用户源代码编译)是否没有使用您不喜欢的api(甚至相反-只使用您允许的api)是一个好主意。部分受信任的代码运行在一个单独的AppDomain中,可以很好地保护您免受不太恶意的代码的攻击。

堆栈溢出通常很难防止,需要在。net中使用自定义主机来处理。长时间运行的任务可以用Thread终止。中止或关闭带有用户代码的AppDomain。

我推荐。net (c#, VB和f#)。您可以利用JIT让服务器以编程方式编译代码,使用反射对其进行分析,并让每个客户机在单独的AppDomain中运行,以实现安全性和代码隔离。

Java有SecurityManager的概念,它使您能够微调在虚拟机中可以或不可以运行的内容。

它还允许您编译代码并在运行时加载生成的类。然后,您可以运行这些类中的任何代码,只要SecurityManager不会因为不允许操作而抛出SecurityException。

这篇文章展示了一个在运行时编译、加载和运行一些代码(作为文本源代码提供)的人为示例。

另一篇文章给出了运行不受信任(和潜在恶意)代码的指导。

如果您想运行最终用户提供的代码,并且希望使用他们可能已经知道的语言,为什么不使用JavaScript呢?

在WebWorker(一个与主JavaScript应用隔离的并发线程,不能访问共享内存或全局变量,如Window对象和DOM,只有一个与主线程通信的通道)中沙箱JavaScript是可能的。

我能想到的唯一安全问题是限制硬件资源的消耗,但我还没有研究过——这很可能与JavaScript运行时之一。您还需要找到一种方法来防止一个WebWorker产生额外的WebWorker。你必须添加一些额外的代码来确保某人的WebWorker在一定时间后自动关闭。

我还没有尝试过服务器端WebWorkers,但从它的外观来看,NodeJS, Rhino和PhantomJS都支持它。Node和Rhino提供了不同于典型web浏览器的环境,而PhantomJS是一个完整的浏览器引擎(WebKit)。从WebWorker的角度来看,它们可能看起来都是一样的。

如果你真的想要"众所周知",ADsafe是JavaScript的一个子集,它是有效的沙盒,尽管它有一些奇怪的(例如避免this)。

Java有"类加载器",它可以限制一个类可以访问的类(参见SecureClassLoader)。我不太清楚细节,但它本质上是用来提供Java applet安全性的。我不知道它是否可以限制内存使用,但限制CPU时间并不太难(不要让它产生线程并在超时后杀死运行不受信任代码的线程)。

(我很高兴地想起了《Robocode》,它运行不受信任的AI,试图在游戏约束下杀死其他不受信任的AI。主要的区别在于,它是在终端用户的电脑上运行的,尽管也有一些网站进行自动排名。这是我对Java的介绍,虽然我注意到它现在支持。net,可能是由于这两种语言的相似性。