Java 保护字段不受反射-系统安全的奇怪情况

Java 保护字段不受反射-系统安全的奇怪情况,java,security,reflection,Java,Security,Reflection,我目前正在研究java安全性,遇到了一个奇怪的现象。java中的SecurityManager存储在java.lang.System中的“security”字段中。有趣的是,这个领域似乎受到了保护,不受反射访问的影响,这是有意义的,但据我所知,这个领域是唯一一个有意义的领域。下面是一个例子: for(Field f : System.class.getDeclaredFields()) System.out.println(f); 输出 public static final java

我目前正在研究java安全性,遇到了一个奇怪的现象。java中的SecurityManager存储在java.lang.System中的“security”字段中。有趣的是,这个领域似乎受到了保护,不受反射访问的影响,这是有意义的,但据我所知,这个领域是唯一一个有意义的领域。下面是一个例子:

for(Field f : System.class.getDeclaredFields())
    System.out.println(f);
输出

public static final java.io.InputStream java.lang.System.in
public static final java.io.PrintStream java.lang.System.out
public static final java.io.PrintStream java.lang.System.err
private static volatile java.io.Console java.lang.System.cons
private static java.util.Properties java.lang.System.props
private static java.lang.String java.lang.System.lineSeparator
有趣的是:字段声明为

private static volatile SecurityManager security = null;
不在列表中,并且确实有一个呼叫

System.class.getDeclaredField("security"); 

产生一个nosuchfield异常。由于我在网上找不到有关此字段的任何信息,而且我非常确定此字段过去可以通过反射访问(例如,请参阅2010年的这篇文章,其中描述了访问此字段),我想知道a)这是一个快速修复,以防止通过反射轻松禁用securitymanager,b)这是如何实现的(或者更确切地说,是否有可能保护其他私有字段不被反射)。

首先,防止反射的方式可能是一种肮脏的
,如果在字段获取机制下的JVM中:

if (strcmp(field, "security") == 0 && strcmp(class, "java.lang.System")) {
    return NULL;
(我无意暗示这是JVM中的实际代码!!)


这显然是大多数java用户无法接受的,因此唯一的其他选择是安装一个不允许私有字段和方法访问的安全管理器。这是可能的,但我不确定如何实现。

一位同事指出,答案不在jvm中,而在jdk中,更准确地说是在sun.reflect.Reflection类中。您将看到查找执行以下操作的静态初始值设定项

static {
    Map<Class,String[]> map = new HashMap<Class,String[]>();
    map.put(Reflection.class,
        new String[] {"fieldFilterMap", "methodFilterMap"});
    map.put(System.class, new String[] {"security"});
    fieldFilterMap = map;

    methodFilterMap = new HashMap<Class,String[]>();
}
其中filterFields实现为

public static Field[] filterFields(Class containingClass,
                                   Field[] fields) {
    if (fieldFilterMap == null) {
        // Bootstrapping
        return fields;
    }
    return (Field[])filter(fields, fieldFilterMap.get(containingClass));
}

因此..这解决了字段如何受到保护的问题。但是,我仍然很好奇为什么要实现这一点。

不授予java.lang.reflect.ReflectPermission“suppressAccessChecks”权限就可以通过SecurityManager拒绝私有字段和方法访问。但是,这是“固定的”在jvm中似乎是一个非常粗糙的黑客。你知道任何文档吗?似乎不是这样。至少快速搜索“安全性”在hotspot vm中,源代码不会触发任何类似的事件。@acerberus hotspot vm?这不是JVM,它是即时编译器。在那里找不到它。我不知道有任何文档显示这一点,这只是我能想到的唯一方法。如果我没记错的话,这个字段不可访问是c中引入的补丁的结果在Java小程序中丢失一个安全漏洞。不是100%确定。这确实很有趣,因为如果有反射,有两种不同的方法可以禁用securitymanager。很好的发现,+1。你从哪里获得
sun.*
类的源代码?或者你只是在使用一个非常好的反编译器?你可以下载代码在那里你还可以找到一个关于如何检查mercurial存储库的教程。
public static Field[] filterFields(Class containingClass,
                                   Field[] fields) {
    if (fieldFilterMap == null) {
        // Bootstrapping
        return fields;
    }
    return (Field[])filter(fields, fieldFilterMap.get(containingClass));
}