当前位置: 首页 > 面试题库 >

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

丁成弘
2023-03-14
问题内容

我对的能力了解得越多,我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());
   }   
   public static void main(String args[]) throws Exception {
      final String s = "Hello world!";
      System.out.println(s); // "Hello world!"
      mutate(s);
      System.out.println(s); // "HELLO WORLD!"
   }
}

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


问题答案:

我需要为此担心吗???

这完全取决于你正在编写哪种类型的程序以及哪种体系结构。

如果你要向世界各地的人们分发名为foo.jar的软件组件,则无论如何你完全会屈从于他们。他们可以修改.jar中的类定义(通过逆向工程或直接字节码操作)。他们可以在自己的JVM中运行你的代码,等等。在这种情况下,担心将无济于事。

如果你正在编写仅通过HTTP与人和系统交互的Web应用程序,并且可以控制应用程序服务器,那么也不必担心。确保你公司的同等编码人员可以创建破坏你单例模式的代码,但前提是他们确实愿意。

如果你将来的工作是在Sun Microsystems / Oracle上编写代码,而你的任务是为Java核心或其他受信任的组件编写代码,那么你应该意识到这一点。但是,担心只会使你掉头发。无论如何,它们可能会让你阅读《安全编码指南》以及内部文档。

如果要编写Java applet,则应注意安全框架。你会发现尝试调用setAccessible的未签名小程序只会导致SecurityException。

setAccessible并不是围绕常规完整性检查的唯一方法。有一个名为sun.misc.Unsafe的非API核心Java类,它可以做几乎所有它想做的事情,包括直接访问内存。本机代码(JNI)也可以绕过这种控制。

在沙盒环境(例如Java Applets,JavaFX)中,每个类都有一组权限,对不安全,setAccessible的访问以及定义的本机实现均由SecurityManager控制。

“ Java访问修饰符并非旨在成为一种安全机制。”

这很大程度上取决于Java代码的运行位置。核心Java类确实使用访问修饰符作为强制执行沙箱的安全机制。

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

Java核心类使用它作为一种简单的方法来访问出于安全原因而必须保持私有的内容。作为示例,Java序列化框架在反序列化对象时使用它来调用私有对象构造函数。有人提到System.setErr,这将是一个很好的示例,但是奇怪的是System类方法setOut / setErr / setIn都使用本机代码来设置final字段的值。

另一个明显的合法用途是需要窥探对象内部的框架(持久性,Web框架,注入)。

在我看来,调试器不属于此类,因为它们通常不在同一JVM进程中运行,而是使用其他方法(JPDA)与JVM进行接口。

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

要回答这个问题,这是一个很深的问题。我想是的,但是你需要添加一些其他机制,而这些机制可能并不是所有的首选。

你可以将setAccessible限制为仅合法使用吗?

你可以应用的最简单的OOTB限制是拥有SecurityManager并只允许setAccessible来访问来自某些来源的代码。这是Java已经做的-允许来自JAVA_HOME的标准Java类执行setAccessible,而不允许来自foo.com的未签名applet类进行setAccessible。如前所述,这种许可是二进制的,就某种意义上来说,无论该许可与否。没有明显的方法允许setAccessible修改某些字段/方法而不允许其他字段/方法。但是,使用SecurityManager可以禁止类完全引用某些包,无论有无反射。

无论SecurityManager的配置如何,我都可以编写可设置setAccessible-proof的类吗?…还是由谁来管理配置?

你不能,而且你当然可以。



 类似资料:
  • 问题内容: 我在AngularJS中使用ngChange来触发自定义函数,该函数将删除用户添加到输入中的所有字母。 问题是我需要定位触发的输入,以便删除输入的字母。我已经在Google上寻找了很长时间,并且对此一无所获。 我能做什么? 问题答案: 简单的方法 ,如果适用于您的用例,请使用type =“ number” : 另一种简单的方法: ng- pattern 也可用于定义正则表达式,以限制字

  • 我已经编写了basic程序,但是,我需要使它这样,如果输入了一个以上的字符,一个错误消息将显示。 }

  • 问题内容: 我正在尝试进行多项选择调查,以允许用户从选项1-x中进行选择。如何做到这一点,以便用户输入除数字以外的任何字符,返回“那是无效答案”之类的内容 问题答案: 您的代码将变为: 它的工作方式是使循环无限循环,直到仅放入数字为止。因此,如果我输入“ 1”,它将破坏循环。但是如果我放“ Fooey!” 该语句将捕获“将引发的错误” ,并且该循环将循环,因为它没有被破坏。

  • 我对谷歌的android地图api完全陌生,我想知道是否有可能将地图显示的区域限制在一个国家。我的意思是,我的目标用户只在我自己的国家,当应用程序逻辑只在这个国家上时,向他们展示整个世界是没有用的,也不符合逻辑的。 有什么想法吗? PS:如果在谷歌的api中不可能,有没有办法用另一个api从另一个提供映射服务的源中做到这一点?

  • 问题内容: 我想将用户限制在一个目录及其子目录中,但是“父目录”按钮允许他们浏览到任意目录。 我应该怎么做呢? 问题答案: 您可能可以通过设置自己的FileSystemView来实现。

  • 我有一个叫做com的方法。ACM软件。共享。AbstractDerrivedBean。getDerivedUniqueId()。当我JProfiler应用程序时,这个方法getDerivedUniqueId()实际上像预期的那样埋在了80个方法的深处。该方法代表应用程序中的每个bean调用。我试图记录CPU调用树,从这个方法开始,一直记录到叶节点(即,被排除的类之一)。 我尝试了以下方法,但没有达