CoderDeng
CoderDeng

Reputation: 15

Java runs custom groovy code ,How to keep groovy safe?

How to prevent user input: System.exit(0) and Infinite loop

Eg:

public class TestGroovy {
    public static ScriptEngineManager factory = new ScriptEngineManager();

    public static void main(String[] args) throws ScriptException, NoSuchMethodException {
        TestGroovy testGroovy = new TestGroovy();
        testGroovy.runGroovy("    def executeMethod(){\n" +
                "        System.exit(0);\n" +
                "    }");
    }


    public void runGroovy(String groovyCode) throws ScriptException, NoSuchMethodException {
        ScriptEngine engine = factory.getEngineByName("groovy");
        engine.eval(groovyCode);
        Invocable invokeEngine = (Invocable) engine;
        invokeEngine.invokeFunction("executeMethod");
    }

}

If people input System.exit(0) or Infinite loop, It's too bad.

I want to block users from entering these.

Thanks ~


One answer I used this method :

public class MySecurityManager extends SecurityManager{

    @Override
    public void checkExit(int status) {
        throw new SecurityException();
    }

}
    public static void main(String[] args) {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("groovy");

        try {
            Map<String,Object> output=new HashMap<>();
            Bindings binding = engine.createBindings();
            binding.put("input",1);
            binding.put("output",output);

            String fact = "def executeMethod(){\n" +
                    "  \tSystem.exit(0);\n" +
                    "    output.put('your key','your value');\n" +
                    "    return output;\n" +
                    "}";
            engine.eval(fact,binding);
            Invocable inv = (Invocable) engine;
            MySecurityManager secManager = new MySecurityManager();
            System.setSecurityManager(secManager);
            output  = (Map<String, Object>) inv.invokeFunction("executeMethod",null);
            System.out.println(output);
        } catch (SecurityException | ScriptException | NoSuchMethodException e) {
            System.out.println("can't input System.exit(0)");
        }
    }

Thanks~

Upvotes: 0

Views: 429

Answers (2)

injecteer
injecteer

Reputation: 20699

I built my groovy execution sandbox based on this article.

SecureASTCustomizer and class/method whitelisting provides you with general solution to protect against many possible misuse of user custom scripts, not only against System.exit(-1). Also, you don't need extra threads or JVM for that.

You can also inject Groovy's annotations to augment your code, like @TimedInterrupt.

Upvotes: 1

Pavel Smirnov
Pavel Smirnov

Reputation: 4799

If you use separate threads to run user-defined code, I can suggest the following:

For System.exit() calls you can define and set your own SecurityManager. It has checkExit() method which tells if System.exit is possible. Override it and provide your logic. The drawback of this solution is that you have to make sure that your application always runs with SecurityManager enabled.

As to infinite loops or any other long-running code I can only suggest an external monitoring thread which in certain conditions (timeout or whatever) would just stop the thread. But this solution has a bunch of problems: you may run into resource leaks or deadlocks if the thread you have stopped owns an unclosed resource (open file, DB connection, etc.) or a lock. Interruption calls in this case won't work since the code may simply ignore them.

As an alternative solution, you can use a separate JVM to run user's code.

It's up to you to decide.

Upvotes: 2

Related Questions