计算机二级

3773考试网计算机等级考试计算机二级正文

如何查看您的JAVA代码是否安全

来源:fjzsksw.com 2010-7-19 14:31:41

 

影响

  在初始化时验证对象确保了数据的完整性。

  例如,请想象为客户创建新帐户的 Account 对象。只有在 Account 期初余额大于 0 时,才可以开设新帐户。可以在构造器里执行这样的验证。有些人未执行构造器而创建 Account 对象,他可能创建了一个具有一些负值的新帐户,这样会使系统不一致,容易受到进一步的干预。

  建议

  在使用对象之前,请检查对象的初始化过程。要做到这一点,每个类都应该有一个在构造器中设置的私有布尔标志,如清单 9 中的类所示。在每个非 static 方法中,代码在任何进一步执行之前都应该检查该标志的值。如果该标志的值为 true ,那么控制应该进一步继续;否则,控制应该抛出一个例外并停止执行。那些从构造器调用的方法将不会检查初始化的变量,因为在调用方法时没有设置标志。因为这些方法并不检查标志,所以应该将它们声明为 private 以防止用户直接访问它们。

  清单 9. 使用布尔标志以检查初始化过程

  Java代码

  public class MyClass{

  private boolean initialized = false;

  //Other variables

  public MyClass (){

  //variable initialization

  method1();

  initialized = true;

  }

  private void method1(){ //no need to check for initialization variable

  //code

  }

  public void method2(){

  try{

  if(initialized==true){

  //proceed with the business logic

  }

  else{

  throw new Exception("Illegal State Of the object");

  }

  }catch(Exception e){

  e.printStackTrace();

  }

  }

  }

  如果对象由逆序列化进行初始化,那么上面讨论的验证机制将难以奏效,因为在该过程中并不调用构造器。在这种情况下,类应该实现 ObjectInputValidation 接口:

  清单 10. 实现 ObjectInputValidation

  Java代码

  interface java.io.ObjectInputValidation {

  public void validateObject() throws InvalidObjectException;

  }

  所有验证都应该在 validateObject() 方法中执行。对象还必须调用 ObjectInputStream.RegisterValidation() 方法以为逆序列化对象之后的验证进行注册。 RegisterValidation() 的第一个参数是实现 validateObject() 的对象,通常是对对象自身的引用。注:任何实现 validateObject() 的对象都可能充当对象验证器,但对象通常验证它自己对其它对象的引用。 RegisterValidation() 的第二个参数是一个确定回调顺序的整数优先级,优先级数字大的比优先级数字小的先回调。同一优先级内的回调顺序则不确定。

  当对象已逆序列化时, ObjectInputStream 按照从高到低的优先级顺序调用每个已注册对象上的 validateObject() 。

  不要通过名称来比较类

  有时候,您可能需要比较两个对象的类,以确定它们是否相同;或者,您可能想看看某个对象是否是某个特定类的实例。因为 JVM 可能包括多个具有相同名称的类(具有相同名称但却在不同包内的类),所以您不应该根据名称来比较类。

  影响

  如果根据名称来比较类,您可能无意中将您不希望授予别人的权利授予了闯入者的类,因为闯入者可以定义与您的类同名的类。

  例如,请假设您想确定某个对象是否是类 com.bar.Foo 的实例。清单 11 演示了完成这一任务的错误方法:

  清单 11. 比较类的错误方法

  Java代码

  if(obj.getClass().getName().equals("Foo"))   // Wrong!

  // objects class is named Foo

  }else{

  // object's class has some other name

  }

  建议

  在那些非得根据名称来比较类的情况下,您必须格外小心,必须确保使用了当前类的 ClassLoader 的当前名称空间,如清单 12 中所示:

  清单 12. 比较类的更好方法

  Java代码

  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. 直接比较对象来看它们是否相等

  Java代码

  if(a.getClass() == b.getClass()){

  // objects have the same class

  }else{

  // objects have different classes

  }

  尽可能少用直接名称比较。

  不要使用内部类

  Java 字节码没有内部类的概念,因为编译器将内部类转换成了普通类,而如果没有将内部类声明为 private ,则同一个包内的任何代码恰好能访问该普通类。

  影响

  因为有这一特性,所以包内的恶意代码可以访问这些内部类。如果内部类能够访问括起外部类的字段,那么情况会变得更糟。可能已经将这些字段声明为 private ,这样内部类就被转换成了独立类,但当内部类访问外部类的字段时,编译器就将这些字段从专用(private)的变为在包(package)的作用域内有效的。内部类暴露了已经够糟糕的了,但更糟糕的是编译器使您将某些字段成为 private 的举动成为徒劳。

  建议

  如果能够不使用内部类就不要使用内部类。

  对付低严重性暴露的技巧

  请遵循下列建议以避免低严重性静态安全性暴露:

  ·避免返回可变对象

  ·检查本机方法

  避免返回可变对象

  Java 方法返回对象引用的副本。如果实际对象是可改变的,那么使用这样一个引用调用程序可能会改变它的内容,通常这是我们所不希望见到的。

 

上一页  [1] [2] [3] [4] [5] 下一页

触屏版 电脑版
3773考试网 琼ICP备12003406号-1