我目前正在研究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");
产生NoSuchFieldException。由于我在网上找不到这方面的任何信息,我很确定这个字段过去是可以通过反射访问的(例如,也可以参见2010年的这篇博客文章,其中描述了访问这个字段)我想知道a)这是作为一个快速解决方案来实现的,以防止通过反射轻易禁用安全管理器吗?b)这是如何实现的(或者更确切地说,是否有机会保护其他私人字段不受反射的影响)。
一位同事指出,答案不在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[]>();
}
如果我们现在仔细观察java.lang.Class中的getDeclaredFields方法,我们会发现这些字段是使用对Reflection类的调用进行过滤的:
Reflection.filterFields(this, getDeclaredFields0(publicOnly));
其中filterFields被实现为
public static Field[] filterFields(Class containingClass,
Field[] fields) {
if (fieldFilterMap == null) {
// Bootstrapping
return fields;
}
return (Field[])filter(fields, fieldFilterMap.get(containingClass));
}
所以。。这解决了如何保护字段的问题。然而,我仍然很好奇为什么要这样做。
首先,防止反射的方法可能是JVM中字段获取机制下的脏if
:
if (strcmp(field, "security") == 0 && strcmp(class, "java.lang.System")) {
return NULL;
(我无意暗示这是JVM中的实际代码!!)
这显然是大多数java用户无法访问的,因此唯一的其他选择是安装一个不允许私有字段和方法访问的安全管理器。这是可能的,但我不确定怎么做。