为当前线程禁用 Java 反射

Posted

技术标签:

【中文标题】为当前线程禁用 Java 反射【英文标题】:Disable Java reflection for the current thread 【发布时间】:2010-10-20 17:10:46 【问题描述】:

我需要调用一些半可信的 Java 代码,并希望在该代码执行期间禁用使用反射的功能。

try
   // disable reflection somehow
   someObject.method();

finally
   // enable reflection again

这可以通过 SecurityManager 来实现吗?如果可以,如何实现?

澄清/上下文:这是another question 的后续内容,关于限制可以从 javascript/Rhino 调用的包。接受的答案引用了一篇关于如何做到这一点的博客条目,它需要两个步骤,第一个步骤使用 Rhino API (ClassShutter),第二个步骤关闭反射和 Class.forName()。我在想我可以使用 SecurityManager 更干净地完成第二步(了解 SecurityManager,正如已经指出的那样,这是一个复杂的过程)。

总而言之,我希望(从代码,而不是设置文件)关闭 Class.forName() 以及对整个反射包的任何访问。

【问题讨论】:

我不确定 SecurityManager 的工作原理,但请查看以下问题:http://***.com/questions/762459/how-to-disable-java-security-manager 【参考方案1】:

这取决于您要限制的内容。

一般来说,可公开访问的 API 不受限制。但是,只要您不授予不可信代码ReflectPermission("suppressAccessChecks") 权限,它就无法访问其他包中的非公共API。

如果您有想要限制所有访问权限的软件包列表,则有两个步骤。首先,在Security 属性中,include the restricted package in the package.access list。然后给你的信任代码RuntimePermission("accessClassInPackage." + pkg)

区分不受信任代码的常用方法是从不同位置加载它,并在授予权限时参考策略文件中的不同代码库。

Java 安全架构非常强大,但我知道它也很复杂;如果你想要一个更具体的例子,请准确描述你想要限制的调用,我会尽量更明确。


在不修改java.policy 文件和/或java.security 文件的情况下做你想做的事情会非常困难,也许是不可能的。 java.security.Policy 代表java.policy 中的信息,但它不提供写访问权限。只要任何现有的SecurityManager 允许,您就可以创建自己的Policy 实现并在运行时安装它。

另一方面,您可以将自定义 java.policy 文件指定为命令行选项。如果您要提供带有某种启动器的完整应用程序,那可能很容易实现。它还为您的用户提供了一些透明度。经验丰富的用户可以查看您希望授予应用程序的权限。

【讨论】:

我在问题中添加了一些上下文。【参考方案2】:

好吧,您可以覆盖SecurityManager.checkMemberAccess 并给出更严格的定义。但是,它实际上并不是这样工作的。例如,如果代码定义了终结器,会发生什么?

关于澄清:其他 API 使用反射和其他 API。例如,java.beans、LiveConnect 和 Rhino。例如,攻击者可以从脚本中创建一个没有快门的新 Rhino 上下文,从而引导进入完整的 JRE。使用开放系统,黑名单永远无法完成。

总而言之:要使用 Java 安全模型,您需要使用它,而不是反对它。

【讨论】:

这是一个很好的答案! What happens for instance if the code defines a finaliser? 是一个很好的问题,当您从攻击者的角度查看类加载器时,如果执行“动态半可信源”被证明是一个坏主意。一个更好的主意是要么获得可信来源(希望是开源的),要么在它自己的 JVM 实例中运行整个 java 程序,并通过内核级 API(如网络、文件系统 API 等)对该 JVM 进行编程控制。跨度> @AkshayaShanbhogue 使用细粒度最小化信任绝对是您想要的安全性。不幸的是,Java 支持全局状态,至少从 1960 年代早期就知道这个想法很糟糕,这是大多数 Java 安全问题的根本原因。如果不是全局变量,就不会有SecurityManager @tom-hawtin-tackline 看来您已经深入思考了这些问题。你能想出一个需要反思的合理情况吗?另外,您认为拥有更精细的粒度控制和移除全局状态是否会对运行时性能产生影响? @AkshayaShanbhogue 评论是两个有用的小回答。绝大多数反射使用都是黑客攻击。动态加载代码时,绝对需要(一次)反射。 / 没有全局状态对性能很有好处。静态初始化器?消失了,因此更容易优化代码加载。此外,全局变量往往会导致瓶颈。【参考方案3】:

我写了一个 ClassShutter 的替代品,它允许对每个实例、每个方法、每个字段进行细粒度的访问控制:

http://riven8192.blogspot.com/2010/07/java-rhino-fine-grained-classshutter.html

【讨论】:

以上是关于为当前线程禁用 Java 反射的主要内容,如果未能解决你的问题,请参考以下文章

JVM及反射

太厉害了!java反射获取方法以及调用方法

java基础(反射,注解,多线程,juc)

Java多线程学习篇Lock

为何mysql中总是有sleep线程?怎样产生的

mysql的sleep线程是啥意思