简单来说
Jython 在带有安全管理器的 JVM 中运行。安全管理器不应阻止 Jython 引擎本身完成其工作,但不应允许在 Jython 中运行的 python 脚本执行任何特权操作。实现此目的的最低 Java 安全策略是什么?
换句话说(长版)
这个问题是关于使用 Java 的安全机制对不受信任的 python 脚本进行沙箱处理。(我不想讨论沙箱 python 的其他方法。)如果这种安全方法存在根本问题,请说出来。
不受信任的 python 代码将调用受信任的 Java 对象上的方法,并将作为 PyObject 嵌入到 Java 中。这在Jythonbook 的示例中进行了解释,我们将使用该示例中的代码。这是 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
调用中运行某些代码。)
伟大的。下一个必需的权限是一个非常危险的权限:危险的 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 中的哪些类需要授权,它们需要哪些特定权限?
而且,如果这种方法注定要失败,那么对这种效果的回答将是很好的。