diff --git a/src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java b/src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java index 8002bed7..13eab1ef 100644 --- a/src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java +++ b/src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java @@ -448,6 +448,37 @@ public Map requireScript(final String path) throws IOException { } } + /** + * Configure the evaluator into sandbox mode for security, it means: + * + * + * For more information on security, please refer to the + * documentation + * + * @since 5.4.3 + * + */ + public void enableSandboxMode() { + disableFeature(Feature.Module); + disableFeature(Feature.NewInstance); + disableFeature(Feature.InternalVars); + disableFeature(Feature.StaticMethods); + setFunctionMissing(null); + setOption(Options.MAX_LOOP_COUNT, 65535); + setOption(Options.ALLOWED_CLASS_SET, Collections.emptySet()); + setOption(Options.ASSIGNABLE_ALLOWED_CLASS_SET, Collections.emptySet()); + setOption(Options.EVAL_TIMEOUT_MS, 1000L); + } + /** * Adds a module class and import it's public static methods as module's exports into module * cache, return the exports map. @@ -701,8 +732,10 @@ public void setOption(final Options opt, final Object val) { * @param feature */ public void enableFeature(final Feature feature) { - this.options.get(Options.FEATURE_SET).featureSet.add(feature); - this.options.get(Options.FEATURE_SET).featureSet.addAll(feature.getPrequires()); + Set featureSet = new HashSet<>(this.options.get(Options.FEATURE_SET).featureSet); + featureSet.add(feature); + featureSet.addAll(feature.getPrequires()); + setOption(Options.FEATURE_SET, featureSet); loadFeatureFunctions(); } @@ -733,10 +766,12 @@ public boolean isFeatureEnabled(final Feature feature) { * @param feature */ public void disableFeature(final Feature feature) { - this.options.get(Options.FEATURE_SET).featureSet.remove(feature); + Set featureSet = new HashSet<>(this.options.get(Options.FEATURE_SET).featureSet); + featureSet.remove(feature); for (AviatorFunction fn : feature.getFunctions()) { this.removeFunction(fn); } + this.setOption(Options.FEATURE_SET, featureSet); loadFeatureFunctions(); } diff --git a/src/main/java/com/googlecode/aviator/runtime/type/AviatorString.java b/src/main/java/com/googlecode/aviator/runtime/type/AviatorString.java index 96a7c371..e435f6ba 100644 --- a/src/main/java/com/googlecode/aviator/runtime/type/AviatorString.java +++ b/src/main/java/com/googlecode/aviator/runtime/type/AviatorString.java @@ -26,6 +26,7 @@ import com.googlecode.aviator.exception.ExpressionRuntimeException; import com.googlecode.aviator.runtime.RuntimeUtils; import com.googlecode.aviator.utils.Constants; +import com.googlecode.aviator.utils.Env; import com.googlecode.aviator.utils.TypeUtils; /** @@ -177,7 +178,8 @@ public String getLexeme(final Map env, final boolean warnOnCompi return this.lexeme; } StringSegments segs = null; - BaseExpression exp = (BaseExpression) (env == null ? null : env.get(Constants.EXP_VAR)); + BaseExpression exp = (BaseExpression) ((env == null || !(env instanceof Env)) ? null + : ((Env) env).getExpression()); if (exp != null) { segs = exp.getStringSegements(this.lexeme, this.lineNo); } else { diff --git a/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceCompatibleUnitTest.java b/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceCompatibleUnitTest.java index 60b6fec0..a2136760 100644 --- a/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceCompatibleUnitTest.java +++ b/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceCompatibleUnitTest.java @@ -1,10 +1,13 @@ package com.googlecode.aviator; import static com.googlecode.aviator.TestUtils.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import java.math.MathContext; import org.junit.Before; import org.junit.Test; +import com.googlecode.aviator.exception.ExpressionRuntimeException; +import com.googlecode.aviator.exception.FunctionNotFoundException; import com.googlecode.aviator.exception.UnsupportedFeatureException; public class AviatorEvaluatorInstanceCompatibleUnitTest extends AviatorEvaluatorInstanceUnitTest { @@ -22,6 +25,39 @@ public void testIssue549() { // ignore } + @Test + public void testSandboxMode() { + this.instance.enableSandboxMode(); + try { + this.instance.execute("new java.util.Date()"); + } catch (UnsupportedFeatureException e) { + // ignore + } + + try { + this.instance.execute("Math.abs(-1)"); + } catch (FunctionNotFoundException e) { + // ignore + } + + try { + this.instance.execute("System.exit(1)"); + } catch (FunctionNotFoundException e) { + // ignore + } + + try { + this.instance.execute("Math.PI"); + } catch (ExpressionRuntimeException e) { + // ignore + } + try { + assertNull(this.instance.execute("__env__")); + } catch (UnsupportedFeatureException e) { + + } + } + @Override @Test(expected = UnsupportedFeatureException.class) public void testMaxLoopCount() { diff --git a/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceUnitTest.java b/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceUnitTest.java index 42cae1c3..210ffb50 100644 --- a/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceUnitTest.java +++ b/src/test/java/com/googlecode/aviator/AviatorEvaluatorInstanceUnitTest.java @@ -38,6 +38,7 @@ import com.googlecode.aviator.exception.CompileExpressionErrorException; import com.googlecode.aviator.exception.ExpressionRuntimeException; import com.googlecode.aviator.exception.ExpressionSyntaxErrorException; +import com.googlecode.aviator.exception.FunctionNotFoundException; import com.googlecode.aviator.exception.TimeoutException; import com.googlecode.aviator.exception.UnsupportedFeatureException; import com.googlecode.aviator.lexer.token.OperatorType; @@ -61,6 +62,43 @@ public void setup() { this.instance.setOption(Options.EVAL_TIMEOUT_MS, 100); } + @Test + public void testSandboxMode() { + this.instance.enableSandboxMode(); + try { + this.instance.execute("new java.util.Date()"); + } catch (UnsupportedFeatureException e) { + // ignore + } + + try { + this.instance.execute("Math.abs(-1)"); + } catch (FunctionNotFoundException e) { + // ignore + } + + try { + this.instance.execute("System.exit(1)"); + } catch (FunctionNotFoundException e) { + // ignore + } + + try { + this.instance.execute("Math.PI"); + } catch (ExpressionRuntimeException e) { + // ignore + } + try { + this.instance.execute("while(true) {}"); + } catch (ExpressionRuntimeException e) { + // ignore + } + try { + assertNull(this.instance.execute("__env__")); + } catch (UnsupportedFeatureException e) { + + } + } @Test public void testIssue549() {