我正在开发一些许可代码,因此我希望避免通过反射访问一个或两个类。
我尝试过实现一个SecurityManager但没有成功。
我发现另一种选择是定义我自己的策略文件,但是这需要我在JVM启动时设置它,这违背了我的目的,我希望能够设置一个防止访问特定的SecurityManager许可证类,或在运行时执行此操作的策略。
答案 0 :(得分:1)
Notes&免责声明强>
<强>先决条件强>
确保任何不受信任的代码与受信任的代码隔离。在此上下文中的隔离意味着:
ProtectionDomain
s之间的分离(两个不同级别的两个代码库的两个域&#34;可信度&#34;应该具有不相等的,非暗示的CodeSource
s),和 ClassLoader
秒。虽然第一个通常是足够的,但在授权和可访问性问题之间的界限模糊的情况下,如反射的情况,后两点也是必要的。我将留下解决此问题的详细信息。因为我们在这里,有一个关于术语的说明:既然JDK没有一致地根据上述属性对客户端代码进行授权,我只是简单地指代运行任何一个的代码。三个授权决策时作为隔离单元。
也许最简单的解决方案是防止不受信任的代码访问特定的包:
package.access
中的<JAVA_HOME>/lib/security/java.security
属性或通过java.security.Security#setProperty
将程序包名称附加到相应的安全属性,以编程方式将其声明为受限制。RuntimePermission
"accessClassInPackage." + restrictedPackageName
。但是有一个问题 - 你也希望不受信任的代码能够完全反射访问宇宙的其他部分&#34;,这绝不可能在没有隐含地授予它访问带来沙箱跪在地上,如果它如此喜欢,例如,重新分配System'
s SecurityManager
字段。这导致我们......
<强>目标强>
Permission
类建模,默认Policy
配置可以表达,默认SecurityManager
可以强制执行。<强>非目标强>
我已经玩了上面的一点,here's结果,这不是完美的,甚至没有错误,但希望足以证明这个想法。
简要概述(有关详细信息,请参阅Javadoc)
SelectiveReflectPermission
是授予不受信任代码的权限。虽然无法容纳当前形式的进一步授权属性,但修改它以包含它们应该相当简单。AllUnsafePermission
表示一组不得授予不受信任的代码的权限(除非沙箱完整性无关紧要)。DeniedPermission
和DenyingPolicy
属于同一类here,对前者进行少量修改,以便包含&#34; target&#34;具有无参数构造函数的权限。这些类只增加了表达&#34; deny-like&#34;策略配置中的规则,但没有必要。ReflectionGatekeeper
之后,SelectiveReflectPermission
委托了一些最常用的反射API部分。相同的逻辑可以嵌入到由核心反射调用的自定义SecurityManager
相关方法(主要是#checkPermission(Permission)
)中,客户端代码非常欣赏,而不是必须使用不同的API。但是(那里总是#34;但是&#34;)我选择了这个选项,因为它需要脆弱的&#34;来电敏感&#34;要引入实现的代码,它必须通过调查调用堆栈来收集所需的授权属性,还要考虑递归反射调用,以及多个线程的调用......导致令人惊讶的接近于J2SE之前的东西1.2安全经理。此外,作为一种品味,我更喜欢管理者尽可能少地包含实际的授权逻辑 - 理想情况下它只能作为AccessController
,最终成为Policy
代表,没有捷径或漏洞<强>用法强>
有某种应用程序启动器,或敏感组件的初始化逻辑本身建立安全性(除非成功,否则失败);这看起来如下:
package com.example.trusted.launcher;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Policy;
import java.util.Collections;
import com.example.trusted.security.DenyingPolicy;
public class Launcher {
public static void main(String... args) throws Exception {
/*
* Get the actual main application class, which has hopefully been loaded by a different ClassLoader,
* and resides in a distinct package and ProtectionDomain.
*/
Class<?> realMain = getMainFromArgs(args);
// install a Policy and SecurityManager
/*
* To avoid having to administer .policy configurations at the file system, you could bundle a
* template with your app/lib, replace any CodeSource URLs you don't know until runtime, temp-save
* to the file system (or use some transient URLStreamHandler) and "feed" the corresponding URL to
* the Policy provider. Or better yet, if you can spare the time, implement your own Policy provider
* as a mutable data structure.
*/
String policyConfig = new String(
Files.readAllBytes(Paths.get(Launcher.class.getResource("policy_template.txt").toURI())),
StandardCharsets.UTF_8);
// replace any CodeSource URL placeholders (e.g. with realMain's cs URL)
policyConfig = adjustPolicyConfig(policyConfig);
// temp-save it and hand it over to Policy
Path tmpPolicyFile = Files.createTempFile("policy", ".tmp");
Files.write(tmpPolicyFile, Collections.singletonList(policyConfig));
// leading equals sign ensures only the indicated config gets loaded
System.setProperty("java.security.policy", "=" + tmpPolicyFile.toUri());
// unnecessary if you don't care about deny rules
Policy.setPolicy(new DenyingPolicy());
System.setSecurityManager(new SecurityManager());
Files.delete(tmpPolicyFile);
// filter args and call real main
invokeMain(realMain, args);
}
// ...
}
...虽然潜在的政策配置模板可能是:
// note: curly braces are MessageFormat-escaped
// ---
// trusted code
grant codeBase "{0}" '{'
permission java.security.AllPermission;
'}';
// sandboxed code
grant codeBase "{1}" '{'
// all permissions...
permission java.security.AllPermission;
// ...save for unsafe ones
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.AllUnsafePermission";
// ...with global reflective access via ReflectionGatekeeper
permission com.example.trusted.security.SelectiveReflectPermission;
// ...with the exception of system code and our own com.example.trusted package
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!sun.*!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!com.sun.*!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!com.oracle.*!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!net.java.*!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!java.*!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!javax.*!*!*:*";
// currently it's not possible to express both a base package _and_ its sub-packages in a single permission
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!com.example.trusted!*!*:*";
permission com.example.trusted.security.DeniedPermission "com.example.trusted.security.SelectiveReflectPermission:*!com.example.trusted.*!*!*:*";
'}';
有了这两个部分,一些映射到域{1}
的类将不能够在其隔离单元外的Class
上调用核心反射方法;但是 能够使用ReflectionGatekeeper
作为等价物,在所有情况下除了明确拒绝的那些。