Jython需要哪些安全权限才能成功运行不受信任的Python代码?

时间:2013-07-25 01:24:12

标签: security jython

简而言之

Jython在带有安全管理器的JVM中运行。安全管理器不应该阻止Jython引擎本身完成它的工作,但它不应该允许在Jython中运行的python脚本执行任何特权操作。完成此任务的最低Java安全策略是什么?

换句话说(长版)

这个问题是关于使用Java的安全机制来沙箱不受信任的python脚本。 (我不想讨论有关沙盒python的其他方法。)如果这种安全方法存在根本性的错误,请说明。

不受信任的python代码将调用受信任Java对象上的方法,并将作为PyObject嵌入Java中。这在Jythonbook's example中有解释,我们将使用该示例中的代码。这是Java 1.6上的Jython 2.5.2。

我们需要向安全管理器提供一些非常具体的指令,因为Jython会执行自己的一些特权操作,但它也会执行不受信任的python代码,这些代码不应具有任何特权。

首先,为了安全起见,我们在Java VM中安装了一个SecurityManager:

/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

大。但对我们来说,Building.py是不受信任的代码,所以我们锁定了JVM。问题是,这使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}

安全管理器不允许任何人阅读“user.dir”属性。当然,Jython本身应该可以读取该属性。我可以将其写入这样的策略文件吗?

/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

嗯,不,我不能......因为不受信任的python代码也在python解释器类中运行。所以不受信任的python也会获得这个特权,这很糟糕。

所以我只需要授权一个特定的jython类,在本例中是PySystemState。 (我可能还需要编辑其源代码,以便在doPrivilegedAction调用中运行某些代码。)

大。下一个必需的权限是doozy:危险的createClassLoader权限。

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)

坐在堆栈底部,我们看到PythonInterpreter.exec已触发此访问请求。 exec()必须作为PrivilegedAction运行吗?

所以这个发现过程可能会持续一段时间,我希望有人能够简单地知道答案:Jython中需要授权哪些类,以及他们需要哪些特定权限?

而且,如果这种方法注定要失败,那么这种效果的答案就会很好。

2 个答案:

答案 0 :(得分:6)

对于Jython 2.5.3(我一直使用的版本),最小权限是:

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";

如果您希望脚本能够子类化Java API类,您还需要:

permission java.lang.RuntimePermission "accessDeclaredMembers";

对于createClassLoader权限,这可能是一个问题,但我发现你可以将这个权限授予Jython解释器,而不是通过移动以下类来解释它在解释器中运行的Python代码将Jython jar放入一个单独的jar中。

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

这个单独的jar与标准Jython jar一起放在类路径上,但是在Java安全策略文件中没有被授予任何权限,所以这些类在脚本尝试调用Java API时总是在调用堆栈上,被禁止利用createClassLoader权限。

值得注意的是,利用Python代码的createClassLoader权限并不容易。我能够在Python脚本中完成,但我必须扩展java.secure.SecureClassLoader,这只有在accessDeclaredMembers权限被授予的情况下才有可能。根据您的风险偏好,可能不值得使用Jython jar来阻止createClassLoader,特别是如果您没有授予accessDeclaredMembers

同样值得指出的是createClassLoader修补程序非常容易受到Jython中的更改的影响,而且我只使用Jython 2.5.3进行了测试。

我在blog post中更详细地写了这篇文章。

答案 1 :(得分:0)

查看java沙箱项目(http://blog.datenwerke.net/p/the-java-sandbox.html)。它允许您灵活地设置安全管理器,并在允许哪些类做什么方面更具体。然而,真正保护任意用户代码是很困难的,特别是如果有问题的语言实现(在你的情况下是jython)没有尝试使用最小的私有权限(例如,期望使用反射,类加载器等)。