Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8166e26

Browse files
Added examples of a sandbox for JEXL expressions
1 parent 7df8133 commit 8166e26

4 files changed

Lines changed: 131 additions & 8 deletions

File tree

java/ql/src/experimental/Security/CWE/CWE-094/JexlInjection.qhelp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ and then evaluated, then it may allow the attacker to run arbitrary code.
1414

1515
<recommendation>
1616
<p>
17-
Including user input in a JEXL expression should be avoided.
17+
Including untrusted input in a JEXL expression should be avoided. If it is not possible,
18+
JEXL expressions should be run in a sandbox that allows accessing only
19+
explicitly allowed classes.
1820
</p>
1921
</recommendation>
2022

@@ -23,6 +25,23 @@ Including user input in a JEXL expression should be avoided.
2325
The following example uses untrusted data to build and run a JEXL expression.
2426
</p>
2527
<sample src="UnsafeJexlExpressionEvaluation.java" />
28+
29+
<p>
30+
The next example shows how an untrusted JEXL expression can be run
31+
in a sandbox that allows accessing only methods in the `java.lang.Math` class.
32+
The sandbox is implemented using `JexlSandbox` class that is provided by
33+
Apache Commons JEXL 3.
34+
However, it's recommended to avoid using untrusted input in JEXL expressions.
35+
</p>
36+
<sample src="SaferJexlExpressionEvaluationWithSandbox.java" />
37+
38+
<p>
39+
The next example shows another way how a sandbox can be implemented.
40+
It uses a custom implememtation of `JexlUberspect`
41+
that checks if callees are instances of allowed classes.
42+
Again, it's recommended to avoid using untrusted input in JEXL expressions.
43+
</p>
44+
<sample src="SaferJexlExpressionEvaluationWithUberspectSandbox.java" />
2645
</example>
2746

2847
<references>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public void evaluate(Socket socket) throws IOException {
2+
try (BufferedReader reader = new BufferedReader(
3+
new InputStreamReader(socket.getInputStream()))) {
4+
5+
JexlSandbox onlyMath = new JexlSandbox(false);
6+
onlyMath.white("java.lang.Math");
7+
JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create();
8+
9+
String input = reader.readLine();
10+
JexlExpression expression = jexl.createExpression(input);
11+
JexlContext context = new MapContext();
12+
expression.evaluate(context);
13+
}
14+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
public void evaluate(Socket socket) throws IOException {
2+
try (BufferedReader reader = new BufferedReader(
3+
new InputStreamReader(socket.getInputStream()))) {
4+
5+
JexlUberspect sandbox = new JexlUberspectSandbox();
6+
JexlEngine jexl = new JexlBuilder().uberspect(sandbox).create();
7+
8+
String input = reader.readLine();
9+
JexlExpression expression = jexl.createExpression(input);
10+
JexlContext context = new MapContext();
11+
expression.evaluate(context);
12+
}
13+
14+
private static class JexlUberspectSandbox implements JexlUberspect {
15+
16+
private static final List<String> ALLOWED_CLASSES =
17+
Arrays.asList("java.lang.Math", "java.util.Random");
18+
19+
private final JexlUberspect uberspect = new JexlBuilder().create().getUberspect();
20+
21+
private void checkAccess(Object obj) {
22+
if (!ALLOWED_CLASSES.contains(obj.getClass().getCanonicalName())) {
23+
throw new AccessControlException("Not allowed");
24+
}
25+
}
26+
27+
@Override
28+
public JexlMethod getMethod(Object obj, String method, Object... args) {
29+
checkAccess(obj);
30+
return uberspect.getMethod(obj, method, args);
31+
}
32+
33+
@Override
34+
public List<PropertyResolver> getResolvers(JexlOperator op, Object obj) {
35+
checkAccess(obj);
36+
return uberspect.getResolvers(op, obj);
37+
}
38+
39+
@Override
40+
public void setClassLoader(ClassLoader loader) {
41+
uberspect.setClassLoader(loader);
42+
}
43+
44+
@Override
45+
public int getVersion() {
46+
return uberspect.getVersion();
47+
}
48+
49+
@Override
50+
public JexlMethod getConstructor(Object obj, Object... args) {
51+
checkAccess(obj);
52+
return uberspect.getConstructor(obj, args);
53+
}
54+
55+
@Override
56+
public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
57+
checkAccess(obj);
58+
return uberspect.getPropertyGet(obj, identifier);
59+
}
60+
61+
@Override
62+
public JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier) {
63+
checkAccess(obj);
64+
return uberspect.getPropertyGet(resolvers, obj, identifier);
65+
}
66+
67+
@Override
68+
public JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg) {
69+
checkAccess(obj);
70+
return uberspect.getPropertySet(obj, identifier, arg);
71+
}
72+
73+
@Override
74+
public JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg) {
75+
checkAccess(obj);
76+
return uberspect.getPropertySet(resolvers, obj, identifier, arg);
77+
}
78+
79+
@Override
80+
public Iterator<?> getIterator(Object obj) {
81+
checkAccess(obj);
82+
return uberspect.getIterator(obj);
83+
}
84+
85+
@Override
86+
public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
87+
return uberspect.getArithmetic(arithmetic);
88+
}
89+
}
90+
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
public void evaluate(Socket socket) throws IOException {
2-
try (BufferedReader reader = new BufferedReader(
2+
try (BufferedReader reader = new BufferedReader(
33
new InputStreamReader(socket.getInputStream()))) {
44

5-
String input = reader.readLine();
6-
JexlEngine jexl = new JexlBuilder().create();
7-
JexlExpression expression = jexl.createExpression(input);
8-
JexlContext context = new MapContext();
9-
expression.evaluate(context);
10-
}
5+
String input = reader.readLine();
6+
JexlEngine jexl = new JexlBuilder().create();
7+
JexlExpression expression = jexl.createExpression(input);
8+
JexlContext context = new MapContext();
9+
expression.evaluate(context);
10+
}
1111
}

0 commit comments

Comments
 (0)