[
https://issues.apache.org/jira/browse/JEXL-381?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17627881#comment-17627881
]
Dmitri Blinov commented on JEXL-381:
------------------------------------
[~henrib] The sandbox is not part of Jexl, rather part of some project that
incorporates Jexl, since there are some project specific pecularities. As I
personally prefer subclassing to delegation, it comprises primaraly of
extensions to Permissions and Uberspect. I don't think it will be of much use
to others as is, but since you're asking I can publish it with some omissions.
The Uberspect deals with some magic around j.n.URI class to override toURL()
method for file schemes. The permissions extension is as follows
{code:java}
public class MyPermissions extends Permissions {
protected static final Set<String> restrictedConstructors =
Collections.unmodifiableSet(new LinkedHashSet<String>(Arrays.asList(
"java.io.File", "java.io.FileDescriptor", "java.io.FileInputStream",
"java.io.FileOutputStream",
"java.io.FilePermission", "java.io.FileReader", "java.io.FileWriter",
"java.io.PrintStream", "java.io.PrintWriter",
"java.io.RandomAccessFile", "java.io.ObjectInputStream",
"java.util.zip.ZipFile", "java.util.jar.JarFile",
"java.net.URL", "java.net.URLClassLoader"
)));
protected boolean isAllowedMethod(Method m) {
if (!Modifier.isPublic(m.getModifiers()))
return false;
if (m.isSynthetic())
return false;
Class<?> clazz = m.getDeclaringClass();
String method = m.getName();
// Prevent direct invocation
if (Class.class.isAssignableFrom(clazz) && ("forName".equals(method) ||
"getClassLoader".equals(method)))
return false;
// Prevent direct invocation
if (Method.class.isAssignableFrom(clazz) && ("invoke".equals(method) ||
"setAccessible".equals(method)))
return false;
// Prevent direct invocation
if (MethodHandle.class.isAssignableFrom(clazz) &&
("invoke".equals(method) || "invokeExact".equals(method)))
return false;
// Prevent direct invocation
if (Constructor.class.isAssignableFrom(clazz) &&
"newInstance".equals(method))
return false;
// Prevent direct invocation
if (File.class.isAssignableFrom(clazz) &&
("createTempFile".equals(method) || "listRoots".equals(method)))
return false;
// Prevent direct invocation
if (URL.class.isAssignableFrom(clazz) &&
"setURLStreamHandlerFactory".equals(method))
return false;
// Prevent direct invocation
if (URLConnection.class.isAssignableFrom(clazz) &&
("setContentHandlerFactory".equals(method) ||
"setDefaultAllowUserInteraction".equals(method) ||
"setDefaultRequestProperty".equals(method) ||
"setFileNameMap".equals(method)))
return false;
// Prevent static method invocations on restricted classes
String name = clazz.getName();
if (MyDefaultContext.PackageResolver.restrictedNames.contains(name) &&
Modifier.isStatic(m.getModifiers()))
return false;
MyPermission msyc = clazz.getAnnotation(MyPermission.class);
MyScripting permission = (msyc != null) ? msyc.scripting() :
MyScripting.ALLOW;
MyPermission msyp = m.getAnnotation(MyPermission.class);
if (msyp != null)
permission = msyp.scripting();
if (permission == MyScripting.RESTRICT)
return false;
return true;
}
/**
* Checks whether a method disallows introspection.
* <p>Since methods can be overridden, this also checks that no superclass
or interface
* explictly disallows this methods.</p>
* @param method the method to check
* @return true if JEXL is allowed to introspect, false otherwise
*/
@Override
public boolean allow(Method method) {
if (method == null)
return false;
if (!isAllowedMethod(method))
return false;
return super.allow(method);
}
/**
* Checks whether a constructor disallows introspection.
* @param ctor the constructor to check
* @return true if JEXL is allowed to introspect, false otherwise
*/
@Override
public boolean allow(Constructor<?> ctor) {
if (ctor == null)
return false;
if (!Modifier.isPublic(ctor.getModifiers()))
return false;
Class<?> clazz = ctor.getDeclaringClass();
if (!allow(clazz))
return false;
String name = clazz.getName();
if (restrictedConstructors.contains(name))
return false;
if (MyDefaultContext.PackageResolver.restrictedNames.contains(name))
return false;
return true;
}
}{code}
> Change default JEXL configuration to a more security-friendly behaviour
> ------------------------------------------------------------------------
>
> Key: JEXL-381
> URL: https://issues.apache.org/jira/browse/JEXL-381
> Project: Commons JEXL
> Issue Type: Improvement
> Affects Versions: 3.2.1
> Reporter: Henri Biestro
> Assignee: Henri Biestro
> Priority: Major
> Fix For: 3.3
>
>
> WHAT:
> JEXL's default builder allows accessing and calling any public method, field
> or constructor of any public class. This might not be desirable since a quick
> exploration of JEXL will quickly conclude the library allows arbitrary
> execution through commands (ProcessBuilder) or getting to the file-system
> through URL or File. This improvement goal is to change JEXL's permeability
> as an explicit option and user decision, not a default behaviour.
> HOW:
> By changing the current JexlBuilder to use a restricted set of permissions
> whilst instantiating the Uberspect, we can ensure a minimal useful set of
> classes can be accessed and only those by default. By removing access to
> almost all classes that interact with the JVM host and file-system, we ensure
> a default isolation that would significantly reduce the ability to use JEXL
> as an attack vector.
> CAVEAT:
> This change will likely break many scripts that were dependant upon the
> default permeability.
> [~ggregory], [~dmitri_blinov] your opinions are welcome :-)
> https://lists.apache.org/thread/kgh0kfkcvllp5mj7kwnpdqrbrfcyyopd
--
This message was sent by Atlassian Jira
(v8.20.10#820010)