在允许用户提交他们自己的代码以由服务器运行的模拟服务器环境中,任何用户提交的代码在沙箱旁边运行显然是有利的,这与浏览器内的小应用程序没有什么不同。我希望能够利用JVM本身,而不是添加另一个VM层来隔离这些提交的组件。
使用现有的Java沙箱模型,这种限制似乎是可能的,但是有没有一种动态的方法来支持运行中的应用程序中用户提交的部分呢?
发布于 2009-02-02 06:24:53
显然,这样的方案会引起各种各样的安全问题。Java有一个严格的安全框架,但它不是微不足道的。不应该忽视搞砸并让非特权用户访问重要系统组件的可能性。
抛开这一警告不谈,如果您以源代码的形式接受用户输入,那么您需要做的第一件事就是将其编译成Java字节码。AFIAK,这不能在本地完成,所以您需要对javac进行系统调用,并将源代码编译为磁盘上的字节码。Here's一个教程,可以作为这方面的起点。Java :正如我在评论中了解到的那样,您实际上可以使用javax.tools.JavaCompiler从源代码中编译代码
一旦有了JVM字节码,就可以使用ClassLoader's defineClass函数将其加载到JVM中。要为这个加载的类设置安全上下文,您需要指定一个ProtectionDomain。ProtectionDomain的最小构造函数需要CodeSource和PermissionCollection。在这里,PermissionCollection是您主要使用的对象-您可以使用它来指定加载的类所具有的确切权限。这些权限最终应该由JVM的AccessController强制执行。
这里有很多可能的错误点,在你实现任何东西之前,你应该非常小心地完全理解所有的东西。
发布于 2013-11-18 05:13:08
是一个用于以有限权限集执行Java代码的库。
它可用于仅允许访问一组白名单中的类和资源。它似乎不能限制对单个方法的访问。它使用一个带有自定义类加载器和安全管理器的系统来实现这一点。
我没有用过它,但它看起来设计得很好,文档也相当好。
@waqas给出了一个非常有趣的答案,解释了这是如何实现你自己的。但将这种安全关键和复杂的代码留给专家要安全得多。
注:该项目自2013年以来就没有更新过,创建者将其描述为“实验性的”。它的主页已经消失了,但Source Forge条目仍然存在。
改编自项目网站的示例代码:
SandboxService sandboxService = SandboxServiceImpl.getInstance();
// Configure context
SandboxContext context = new SandboxContext();
context.addClassForApplicationLoader(getClass().getName());
context.addClassPermission(AccessType.PERMIT, "java.lang.System");
// Whithout this line we get a SandboxException when touching System.out
context.addClassPermission(AccessType.PERMIT, "java.io.PrintStream");
String someValue = "Input value";
class TestEnvironment implements SandboxedEnvironment<String> {
@Override
public String execute() throws Exception {
// This is untrusted code
System.out.println(someValue);
return "Output value";
}
};
// Run code in sandbox. Pass arguments to generated constructor in TestEnvironment.
SandboxedCallResult<String> result = sandboxService.runSandboxed(TestEnvironment.class,
context, this, someValue);
System.out.println(result.get());发布于 2014-08-26 10:32:09
要解决接受答案中的问题,即自定义SecurityManager将应用于JVM中的所有线程,而不是基于每个线程,您可以创建一个自定义SecurityManager,它可以为特定线程启用/禁用,如下所示:
import java.security.Permission;
public class SelectiveSecurityManager extends SecurityManager {
private static final ToggleSecurityManagerPermission TOGGLE_PERMISSION = new ToggleSecurityManagerPermission();
ThreadLocal<Boolean> enabledFlag = null;
public SelectiveSecurityManager(final boolean enabledByDefault) {
enabledFlag = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return enabledByDefault;
}
@Override
public void set(Boolean value) {
SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null) {
securityManager.checkPermission(TOGGLE_PERMISSION);
}
super.set(value);
}
};
}
@Override
public void checkPermission(Permission permission) {
if (shouldCheck(permission)) {
super.checkPermission(permission);
}
}
@Override
public void checkPermission(Permission permission, Object context) {
if (shouldCheck(permission)) {
super.checkPermission(permission, context);
}
}
private boolean shouldCheck(Permission permission) {
return isEnabled() || permission instanceof ToggleSecurityManagerPermission;
}
public void enable() {
enabledFlag.set(true);
}
public void disable() {
enabledFlag.set(false);
}
public boolean isEnabled() {
return enabledFlag.get();
}
}ToggleSecurirtyManagerPermission只是java.security.Permission的一个简单实现,以确保只有授权的代码才能启用/禁用安全管理器。它看起来是这样的:
import java.security.Permission;
public class ToggleSecurityManagerPermission extends Permission {
private static final long serialVersionUID = 4812713037565136922L;
private static final String NAME = "ToggleSecurityManagerPermission";
public ToggleSecurityManagerPermission() {
super(NAME);
}
@Override
public boolean implies(Permission permission) {
return this.equals(permission);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ToggleSecurityManagerPermission) {
return true;
}
return false;
}
@Override
public int hashCode() {
return NAME.hashCode();
}
@Override
public String getActions() {
return "";
}
}https://stackoverflow.com/questions/502218
复制相似问题