Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何创建安全的JEXL(脚本)沙盒?_Java_Jexl - Fatal编程技术网

Java 如何创建安全的JEXL(脚本)沙盒?

Java 如何创建安全的JEXL(脚本)沙盒?,java,jexl,Java,Jexl,我正在为JEXL脚本创建一个沙盒,以便恶意用户无法访问我们授予他们访问权限的变量之外的数据,也无法对服务器执行DOS攻击。我想为其他也这样做的人记录这一点,并让其他人对该方法进行输入 以下是我知道需要解决的事项列表: 仅允许使用白名单上的“new”实例化类 不允许在任何类上访问getClass方法,因为这样可以调用forName,并且可以访问任何类 限制对文件等资源的访问 只允许表达式执行一定的时间,这样我们就可以限制它所消耗的资源量 这不适用于JEXL,但可能适用于您正在使用的脚本语言: 不允

我正在为JEXL脚本创建一个沙盒,以便恶意用户无法访问我们授予他们访问权限的变量之外的数据,也无法对服务器执行DOS攻击。我想为其他也这样做的人记录这一点,并让其他人对该方法进行输入

以下是我知道需要解决的事项列表:

  • 仅允许使用白名单上的“new”实例化类
  • 不允许在任何类上访问getClass方法,因为这样可以调用forName,并且可以访问任何类
  • 限制对文件等资源的访问
  • 只允许表达式执行一定的时间,这样我们就可以限制它所消耗的资源量
  • 这不适用于JEXL,但可能适用于您正在使用的脚本语言:

  • 不允许对象具有自定义finalize方法,因为finalize方法是从finalizer线程调用的,并将使用原始AccessControlContext而不是用于创建对象和执行其中代码的AccessControlContext执行

  • 更新:这一切都是使用JEXL 2.0.1完成的。您可能需要对此进行调整,以使其适用于较新版本。

    以下是我处理这些案件的方法。我已经创建了单元测试来测试这些案例中的每一个,并且我已经验证了它们的有效性

  • JEXL让这变得非常简单。只需创建一个自定义类加载器。重写两个loadClass()方法。在JetEngine上调用setClassLoader()

  • 同样,JEXL让这变得非常简单。必须同时阻止“.class”和“.getClass()”。创建您自己的Uberspect类,该类扩展UberSpectMPL。如果标识符等于“class”,则重写getPropertyGet返回null。重写getMethod,如果方法等于“getClass”,则返回null。构造JetEngine时,请传递对Uberspect实现的引用

    class MyUberspectImpl extends UberspectImpl {
    
        public MyUberspectImpl(Log jexlLog) {
            super(jexlLog);
        }
    
        @Override
        public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) {
            // for security we do not allow access to .class property
            if ("class".equals(identifier)) throw new RuntimeException("Access to getClass() method is not allowed");
            JexlPropertyGet propertyGet = super.getPropertyGet(obj, identifier, info);
            return propertyGet;
        }
    
        @Override
        public JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info) {
            // for security we do not allow access to .getClass() method
            if ("getClass".equals(method)) throw new RuntimeException("Access to getClass() method is not allowed");
            return super.getMethod(obj, method, args, info);
        }
    
    }
    
  • 您可以使用Java的AccessController机制来实现这一点。我将简要介绍一下这项工作。使用-Djava.security.policy=policyfile启动java。创建一个名为policyfile的文件,其中包含以下行: 授予{permission java.security.AllPermission;}; 通过此调用设置默认的SecurityManager:System.setSecurityManager(new SecurityManager());现在你可以控制权限,默认情况下,你的应用程序拥有所有权限。当然,如果你将应用程序的权限限制在它需要的范围内,那就更好了。接下来,创建一个AccessControlContext,将权限限制在最低限度,并调用AccessController.doPrivileged()并传递AccessControlContext,然后在doPrivileged()内执行JEXL脚本。这里有一个小程序演示了这一点。JEXL脚本调用System.exit(1),如果它没有包装在doPrivileged()中,它将成功终止JVM

    System.out.println("java.security.policy=" + System.getProperty("java.security.policy"));
    System.setSecurityManager(new SecurityManager());
    try {
        Permissions perms = new Permissions();
        perms.add(new RuntimePermission("accessDeclaredMembers"));
        ProtectionDomain domain = new ProtectionDomain(new CodeSource( null, (Certificate[]) null ), perms );
        AccessControlContext restrictedAccessControlContext = new AccessControlContext(new ProtectionDomain[] { domain } );
    
        JexlEngine jexlEngine = new JexlEngine();
        final Script finalExpression = jexlEngine.createScript(
                "i = 0; intClazz = i.class; "
                + "clazz = intClazz.forName(\"java.lang.System\"); "
                + "m = clazz.methods; m[0].invoke(null, 1); c");
    
        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
            @Override
            public Object run() throws Exception {
                return finalExpression.execute(new MapContext());
            }
        }, restrictedAccessControlContext);
    }
    catch (Throwable ex) {
        ex.printStackTrace();
    }
    
    下面是我如何实例化JetEngine的:

            Log jexlLog = LogFactory.getLog("JEXL");
            Map <String, Object> functions = new HashMap();
            jexlEngine = new JexlEngine(new MyUberspectImpl(jexlLog), new MyJexlArithmetic(false), functions, jexlLog);
    
    Log jexlLog=LogFactory.getLog(“JEXL”);
    Map functions=newhashmap();
    jexlEngine=新的jexlEngine(新的myuberceppectmpl(jexlLog)、新的myjexl算法(false)、函数、jexlLog);
    
    如何处理
    forName
    可能利用脚本达到恶意目的的情况?Uberspect也没有帮助。或者可能是我用错了。我创建了一个具有自定义Uberspect类的JetEngine,但它从未验证
    .class
    的使用情况。我将添加有关我的实现的更多信息。此外,我确信我使用的JEXL版本比您的版本旧得多。
            Log jexlLog = LogFactory.getLog("JEXL");
            Map <String, Object> functions = new HashMap();
            jexlEngine = new JexlEngine(new MyUberspectImpl(jexlLog), new MyJexlArithmetic(false), functions, jexlLog);