java黑客代码 黑客必备的代码( 五 )


不要通过名称来比较类
有时候,您可能需要比较两个对象的类,以确定它们是否相同;或者,您可能想看看某个对象是否是某个特定类的实例 。因为 JVM 可能包括多个具有相同名称的类(具有相同名称但却在不同包内的类),所以您不应该根据名称来比较类 。
影响
如果根据名称来比较类,您可能无意中将您不希望授予别人的权利授予了闯入者的类,因为闯入者可以定义与您的类同名的类 。
例如,请假设您想确定某个对象是否是类 com.bar.Foo 的实例 。清单 11 演示了完成这一任务的错误方法:
清单 11. 比较类的错误方法
if(obj.getClass().getName().equals("Foo"))// Wrong!
// objects class is named Foo
}else{
// object's class has some other name
}
建议
在那些非得根据名称来比较类的情况下,您必须格外小心,必须确保使用了当前类的 ClassLoader 的当前名称空间,如清单 12 中所示:
清单 12. 比较类的更好方法
if(obj.getClass() == this.getClassLoader().loadClass("com.bar.Foo")){
// object's class is equal to
//the class that this class calls "com.bar.Foo"
}else{
// object's class is not equal to the class that
// this class calls "com.bar.Foo"
}
然而 , 比较类的更好方法是直接比较类对象看它们是否相等 。例如,如果您想确定两个对象 a 和 b 是否属同一个类,那么您就应该使用清单 13 中的代码:
清单 13. 直接比较对象来看它们是否相等
if(a.getClass() == b.getClass()){
// objects have the same class
}else{
// objects have different classes
}
尽可能少用直接名称比较 。
不要使用内部类
Java 字节码没有内部类的概念,因为编译器将内部类转换成了普通类 , 而如果没有将内部类声明为 private,则同一个包内的任何代码恰好能访问该普通类 。
影响
因为有这一特性,所以包内的恶意代码可以访问这些内部类 。如果内部类能够访问括起外部类的字段,那么情况会变得更糟 。可能已经将这些字段声明为 private,这样内部类就被转换成了独立类,但当内部类访问外部类的字段时,编译器就将这些字段从专用(private)的变为在包(package)的作用域内有效的 。内部类暴露了已经够糟糕的了,但更糟糕的是编译器使您将某些字段成为 private 的举动成为徒劳 。
建议 如果能够不使用内部类就不要使用内部类 。
对付低严重性暴露的技巧
请遵循下列建议以避免低严重性静态安全性暴露:
避免返回可变对象
检查本机方法
避免返回可变对象
Java 方法返回对象引用的副本 。如果实际对象是可改变的,那么使用这样一个引用调用程序可能会改变它的内容,通常这是我们所不希望见到的 。
影响
请考虑这个示例:某个方法返回一个对敏感对象的内部数组的引用,假定该方法的调用程序不改变这些对象 。即使数组对象本身是不可改变的 , 也可以在数组对象以外操作数组的内容,这种操作将反映在返回该数组的对象中 。如果该方法返回可改变的对象,那么事情会变得更糟;外部实体可以改变在那个类中声明的 public 变量 , 这种改变将反映在实际对象中 。
清单 14 演示了脆弱性 。getExposedObj() 方法返回了 Exposed 对象的引用副本 , 该对象是可变的:
清单 14. 返回可变对象的引用副本
class Exposed{
private int id;
private String name;
public Exposed(){
}
public Exposed(int id, String name){
this.id = id;
this.name = name;

推荐阅读