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中需要授权哪些类,以及他们需要哪些特定权限?
而且,如果这种方法注定要失败,那么这种效果的答案就会很好。
答案 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)没有尝试使用最小的私有权限(例如,期望使用反射,类加载器等)。