如何将setAccessible限制为仅“合法”使用?

我对的力量了解得越多,我java.lang.reflect.AccessibleObject.setAccessible就越惊讶于它的作用。这是根据我对问题的回答(使用反射更改静态最终File.separatorChar用于单元测试)改编而成的。


import java.lang.reflect.*;


public class EverythingIsTrue {

   static void setFinalStatic(Field field, Object newValue) throws Exception {

      field.setAccessible(true);


      Field modifiersField = Field.class.getDeclaredField("modifiers");

      modifiersField.setAccessible(true);

      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);


      field.set(null, newValue);

   }

   public static void main(String args[]) throws Exception {      

      setFinalStatic(Boolean.class.getField("FALSE"), true);


      System.out.format("Everything is %s", false); // "Everything is true"

   }

}

您可以做真正令人发指的事情:


public class UltimateAnswerToEverything {

   static Integer[] ultimateAnswer() {

      Integer[] ret = new Integer[256];

      java.util.Arrays.fill(ret, 42);

      return ret;

   }   

   public static void main(String args[]) throws Exception {

      EverythingIsTrue.setFinalStatic(

         Class.forName("java.lang.Integer$IntegerCache")

            .getDeclaredField("cache"),

         ultimateAnswer()

      );

      System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42"

   }

}

大概是API设计者意识到了可滥用性setAccessible,但是必须承认它具有合法的用途来提供它。所以我的问题是:


真正合法的用途是setAccessible什么?

Java是否可以被设计为一开始就没有这种需求?

这种设计的负面后果(如果有)是什么?

您setAccessible只能限制合法使用吗?

只有通过SecurityManager吗?

它是如何工作的?白名单/黑名单,粒度等?

必须在您的应用程序中对其进行配置是否常见?

setAccessible无论SecurityManager配置如何,我都可以将自己的类写成-proof 吗?

还是由谁来管理配置?

我猜一个更重要的问题是:我需要为此担心吗???


我的课程都没有任何类似的可执行隐私。现在无法执行单例模式(不考虑其优缺点)。正如我上面的摘录所示,甚至几乎无法保证有关Java基础如何工作的一些基本假设。


这些问题不是真的吗???


好的,我刚刚确认:感谢setAccessible,Java字符串不是不可变的。


import java.lang.reflect.*;


public class MutableStrings {

   static void mutate(String s) throws Exception {

      Field value = String.class.getDeclaredField("value");

      value.setAccessible(true);

      value.set(s, s.toUpperCase().toCharArray());

   }   

 

我是唯一认为这是一个巨大问题的人吗?


慕少森
浏览 993回答 3
3回答

SMILET

真正合法的用途是setAccessible什么?单元测试,JVM内部(例如,实现System.setError(...))等等。Java是否可以被设计为一开始就没有这种需求?这种设计的负面后果(如果有)是什么?很多事情将无法实现。例如,各种Java持久性,序列化和依赖项注入都依赖于反射。几乎所有在运行时都依赖JavaBeans约定的东西。您setAccessible只能限制合法使用吗?只有通过SecurityManager吗?是。它是如何工作的?白名单/黑名单,粒度等?这取决于权限,但我相信使用权限setAccessible是二进制的。如果需要粒度,则需要对要限制的类使用其他类加载器和其他安全管理器。我猜您可以实现一个实现更细粒度逻辑的自定义安全管理器。必须在您的应用程序中对其进行配置是否常见?没有。setAccessible无论SecurityManager配置如何,我都可以将自己的类写成-proof 吗?还是由谁来管理配置?不,你不能,是的。另一种选择是通过源代码分析工具“强制”执行此操作。例如风俗pmd或findbugs规则。或(例如)识别的代码的选择性代码审查grep setAccessible ...。作为对后续行动的回应我的课程都没有任何类似的可执行隐私。现在无法执行单例模式(不考虑其优缺点)。如果那让您担心,那么我想您需要担心。但是,实际上,您不应该试图迫使其他程序员尊重您的设计决策。如果人们愚蠢到可以使用反射无意中创建多个单例实例(例如),那么他们可以承受后果。另一方面,如果您的意思是“隐私”包含保护敏感信息不被泄露的含义,那么您就是在树错误的树。在Java应用程序中保护敏感数据的方法是不允许不信任的代码进入处理敏感数据的安全沙箱中。Java访问修饰符并非旨在成为一种安全机制。<字符串示例>-我是唯一认为这是一个巨大问题的人吗?可能不是唯一的一个:-)。但是海事组织,这不是一个问题。公认的事实是,不应在沙箱中执行不受信任的代码。如果您拥有受信任的代码/受信任的程序员从事此类工作,那么您的问题就会比意外地可变的字符串更糟糕。(想想逻辑炸弹,通过秘密渠道泄露数据等)在您的开发或运营团队中,有许多方法可以解决(或减轻)“不良行为者”的问题。但是它们是昂贵且限制性的...对于大多数用例来说是过大的。

慕的地10843

在这种情况下,反射确实与安全/保障正交。我们如何限制反射?Java具有安全管理器,并且ClassLoader是其安全模型的基础。就您而言,我想您需要看看java.lang.reflect.ReflectPermission。但这并不能完全解决反射问题。可用的反射功能应遵循细粒度的授权方案,而现在情况并非如此。例如,允许某些框架使用反射(例如Hibernate),但不使用其余代码。或者为了调试目的而允许程序仅以只读方式反映。将来可能成为主流的一种方法是使用所谓的镜子将反射功能与类分开。请参阅《镜像:元级设施的设计原则》。但是,还有其他各种研究可以解决这个问题。但是我同意动态语言的问题比静态语言更为严重。我们应该担心反射给我们带来的超级大国吗?是的,没有。是的,因为Java平台应该由Classloader安全管理器保护。破坏反射的能力可以看作是一种突破。没有在这个意义上,大多数系统都是反正不是完全安全的。很多类经常可以被子类化,您可能已经就这样滥用了系统。当然类可以制成final或密封,使他们不能在其他罐子被继承。但是据此,只有少数几个类得到正确保护(例如String)。有关最终课程的详细信息,请参见此答案。另请参阅Sami Koivu的博客,以获取有关安全性的更多Java 技巧。Java的安全性模型在某些方面可以视为不足。诸如NewSpeak之类的某些语言甚至采用了更为激进的模块化方法,在这种方法中,您只能访问依赖关系反转显式提供给您的内容(默认情况下为无)。同样重要的是要注意,安全性始终是相对的。在语言级别,例如,您不能阻止模块形式消耗100%的CPU或消耗所有内存,直到一个OutOfMemoryException。这些问题需要通过其他方式解决。将来我们可能会看到Java扩展了资源利用率配额,但是明天就不行了:)我可以在这个问题上做更多的扩展,但是我认为我已经指出了。
打开App,查看更多内容
随时随地看视频慕课网APP