What security rights does Jython need to successfully execute untrusted Python code?

Briefly

Jython works in the JVM with a security manager. The security manager should not stop the Jython engine itself from doing its job, but it should not allow any privileged python script actions running in Jython. What is the minimum Java security policy that will do this?

In other words (long version)

This question is about using Java security mechanisms for untrusted python scripts for the sandbox. (I do not want to discuss other ways to use the sandbox pinton.) If something is fundamentally wrong with this approach to security, say so.

Invalid python code will call methods on trusted Java objects and will be embedded in Java as PyObject. This is explained in the Jythonbook example , and we will use the code from this example. This is Jython 2.5.2 on Java 1.6.

We need to give some specific instructions to the security manager, as Jython performs some proprietary privileged actions, but also executes untrusted python code that should not have any of these privileges.

First, for security, we install the SecurityManager in the Java virtual machine:

/home/me% export CLASSPATH=.:jython.jar /home/me% javac ./org/jython/book/interfaces/BuildingType.java ./org/jython/book/Main.java ./org/jython/book/util/BuildingFactory.java /home/me% java org.jython.book.Main Building Info: null BUILDING-A 100 WEST MAIN Building Info: null BUILDING-B 110 WEST MAIN Building Info: null BUILDING-C 120 WEST MAIN 

Great. But for us, Building.py is unreliable code, so we are blocking the JVM. The problem is that crippling Jython:

 /home/me% java -Djava.security.manager org.jython.book.Main Jul 23, 2013 7:07:17 PM org.python.google.common.base.internal.Finalizer getInheritableThreadLocalsField INFO: Couldn't access Thread.inheritableThreadLocals. Reference finalizer threads will inherit thread local values. Exception in thread "main" java.security.AccessControlException: access denied (java.util.PropertyPermission user.dir read) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323) at java.security.AccessController.checkPermission(AccessController.java:546) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) ... at java.io.File.getAbsolutePath(File.java:501) at org.python.core.PySystemState.<init>(PySystemState.java:181) at org.python.core.PySystemState.doInitialize(PySystemState.java:890) at org.python.core.PySystemState.initialize(PySystemState.java:800) at org.python.core.PySystemState.initialize(PySystemState.java:750) at org.python.core.PySystemState.initialize(PySystemState.java:743) at org.python.core.PySystemState.initialize(PySystemState.java:737) at org.python.core.PySystemState.initialize(PySystemState.java:733) at org.python.core.ThreadStateMapping.getThreadState(ThreadStateMapping.java:17) at org.python.core.Py.getThreadState(Py.java:1315) at org.python.core.Py.getThreadState(Py.java:1311) at org.python.core.Py.getSystemState(Py.java:1331) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:102) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:92) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:64) at org.jython.book.util.BuildingFactory.<init>(BuildingFactory.java:22) at org.jython.book.Main.main(Main.java:21){code} 

The security manager does not allow anyone to read the user.dir property. Of course, it should be good for Jython to read this property. Can I write this to a policy file like this?

 /home/me% cat jython.policy grant codeBase "/home/me/*" { permission java.util.PropertyPermission "user.dir", "read"; }; /home/me% java -Djava.security.manager -Djava.security.policy=jython.policy org.jython.book.Main 

Well no, I can't ... because untrusted python code also works in python interpreter classes. Thus, an unreliable python will also receive this privilege, and this is bad.

Therefore, I need to authorize only a specific jython class, in this case PySystemState. (I may also need to edit its source code so that it doPrivilegedAction certain code in a doPrivilegedAction call.)

Great. The next required privilege is doozy: the dangerous createClassLoader permission.

 java.security.AccessControlException: access denied (java.lang.RuntimePermission createClassLoader) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323) at java.security.AccessController.checkPermission(AccessController.java:546) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:594) at java.lang.ClassLoader.<init>(ClassLoader.java:226) at java.security.SecureClassLoader.<init>(SecureClassLoader.java:76) at java.net.URLClassLoader.<init>(URLClassLoader.java:113) at org.python.core.BytecodeLoader$Loader.<init>(BytecodeLoader.java:81) at org.python.core.BytecodeLoader.makeClass(BytecodeLoader.java:27) at org.python.core.BytecodeLoader.makeCode(BytecodeLoader.java:67) at org.python.compiler.LegacyCompiler$LazyLegacyBundle.loadCode(LegacyCompiler.java:43) at org.python.core.CompilerFacade.compile(CompilerFacade.java:34) at org.python.core.Py.compile_flags(Py.java:1703) at org.python.core.Py.compile_flags(Py.java:1708) at org.python.core.Py.compile_flags(Py.java:1738) at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:206) at org.jython.book.util.BuildingFactory.<init>(BuildingFactory.java:23) at org.jython.book.Main.main(Main.java:22) 

Hidden at the bottom of the stack, we see that PythonInterpreter.exec triggered this access request. Is exec() executed as a PrivilegedAction?

So this discovery process could go on for some time, and I was hoping that someone would just find out the answer: what classes in Jython should be authorized and what specific permissions do they need?

And if this approach is doomed to failure, then the answer to this question will be great.

+6
source share
2 answers

For Jython 2.5.3 (the version I used) minimum permissions:

 permission java.lang.RuntimePermission "createClassLoader"; permission java.lang.RuntimePermission "getProtectionDomain"; permission java.io.FilePermission "${user.dir}/*", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "user.dir", "read"; permission java.util.PropertyPermission "line.separator", "read"; 

If you want scripts to be able to subclass Java API classes, you will also need:

 permission java.lang.RuntimePermission "accessDeclaredMembers"; 

Regarding the createClassLoader permission, this may be a problem, but I found that you can grant this permission to the Jython interpreter without giving it the Python code running in the interpreter by moving the following classes from the Jython jar to a separate jar.

 org.python.core.PyReflectedConstructor org.python.core.PyReflectedField org.python.core.PyReflectedFunction 

This separate jar is placed in the class path along with the standard jython jar, but no permissions are granted in the Java security policy file, and therefore these classes, which are always in the call stack when scripts try to call the Java API, cannot use the createClassLoader permission.

It's also worth noting that it is not easy to use createClassLoader permission from Python code. I was able to make a script from Python, but I had to extend java.secure.SecureClassLoader , which is only possible if accessDeclaredMembers permission is also allowed. Depending on your risk appetite, you might not want to mix with Jython banks to block createClassLoader , especially if you do not provide accessDeclaredMembers .

It's also worth noting that the createClassLoader patch createClassLoader very sensitive to changes inside Jython, and I only tested it with Jython 2.5.3.

I wrote this in more detail in a blog post .

+5
source

Check out the java sandbox project ( http://blog.datenwerke.net/p/the-java-sandbox.html ). This allows you to flexibly configure the security manager and be more specific in terms of which classes can do what. However, it is difficult to really protect arbitrary user code, especially if the language implementation in question (in your case jython) does not try to use minimal privieleges (for example, expects to use reflection, class loaders, etc.).

0
source

Source: https://habr.com/ru/post/950219/


All Articles