Skip to content

Commit

Permalink
feat: adds enableSandboxMode method to enable sandbox mode
Browse files Browse the repository at this point in the history
  • Loading branch information
killme2008 committed Jun 10, 2024
1 parent 3716a6c commit 5de8560
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 4 deletions.
41 changes: 38 additions & 3 deletions src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,37 @@ public Map<String, Object> requireScript(final String path) throws IOException {
}
}

/**
* Configure the evaluator into sandbox mode for security, it means:
* <ul>
* <li>Disable syntax feature: Module, NewInstance, StaticMethods and InternalVars,</li>
* <li>Disable reflection invocation by function missing,</li>
* <li>Set the single maximum loop counter to 65535,</li>
* <li>Set ALLOWED_CLASS_SET and ASSIGNABLE_ALLOWED_CLASS_SET to be empty, disable all classes to
* be accessed via static fields or methods,</li>
* <li>Set the EVAL_TIMEOUT_MS to be 1000 milliseconds(1 second), which means the execution
* timeout.
* <li>
* </ul>
*
* For more information on security, please refer to the
* <a href="https://www.yuque.com/boyan-avfmj/aviatorscript/ou23gy#elOSu">documentation</a>
*
* @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.
Expand Down Expand Up @@ -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<Feature> featureSet = new HashSet<>(this.options.get(Options.FEATURE_SET).featureSet);
featureSet.add(feature);
featureSet.addAll(feature.getPrequires());
setOption(Options.FEATURE_SET, featureSet);
loadFeatureFunctions();
}

Expand Down Expand Up @@ -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<Feature> 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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -177,7 +178,8 @@ public String getLexeme(final Map<String, Object> 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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand Down

0 comments on commit 5de8560

Please sign in to comment.