建议
一般来说,应该使用取值方法而不是 public 变量。按照具体问题具体对待的原则,在确定哪些变量特别重要因而应该声明为 private 时,请将编码的方便程度及成本同安全性需要加以比较。清单 2 演示了以下列方式来使之安全的代码:
清单 2. 不带有 public 变量的代码
Java代码
class Test {
private int id;
private String name;
Test(){
id = 1;
name = "hello world";
}
public void setId(int id){
this.id = id;
}
public void setName(String name){
this.name = name;
}
public int getId(){
return id;
}
public String getName(){
return name;
}
}
让每个类和方法都为 final
不允许扩展的类和方法应该声明为 final 。这样做防止了系统外的代码扩展类并修改类的行为。
影响
仅仅将类声明为非 public 并不能防止攻击者扩展类,因为仍然可以从它自己的包内访问该类。
建议
让每个类和方法都成为 final,除非有足够的理由不这样做。按此建议,我们要求您放弃可扩展性,虽然它是使用诸如 Java 语言之类的面向对象语言的主要优点之一。在试图提供安全性时,可扩展性却成了您的敌人;可扩展性只会为攻击者提供更多给您带来麻烦的方法。
不要依赖包作用域
没有显式地标注为 public 、 private 或 protected 的类、方法和变量在它们自己的包内是可访问的。
影响
如果 Java 包不是封闭的,那么攻击者就可以向包内引入新类并使用该新类来访问您想保护的内容。诸如 java.lang 之类的一些包缺省是封闭的,一些 JVM 也让您封闭自己的包。然而,您最好假定包是不封闭的。
建议
从软件工程观点来看,包作用域具有重要意义,因为它可以阻止对您想隐藏的内容进行偶然的、无意中的访问。但不要依靠它来获取安全性。应该将类、方法和变量显式标注为 public 、 private 或 protected 中适合您特定需求的那种。
使类不可克隆
克隆允许绕过构造器而轻易地复制类实例。
影响
即使您没有有意使类可克隆,外部源仍然可以定义您的类的子类,并使该子类实现 java.lang.Cloneable 。这就让攻击者创建了您的类的新实例。拷贝现有对象的内存映象生成了新的实例;虽然这样做有时候是生成新对象的可接受方法,但是大多数时候是不可接受的。清单 3 说明了因为可克隆而暴露的代码:
清单 3. 可克隆代码
Java代码
class MyClass{
private int id;
private String name;
public MyClass(){
id=1;
name="HaryPorter";
}
public MyClass(int id,String name){
this.id=id;
this.name=name;
}
public void display(){
System.out.println("Id ="+id+"\n"+"Name="+name);
}
}
// hackers code to clone the user class
public class Hacker extends MyClass implements Cloneable {
public static void main(String[] args){
Hacker hack=new Hacker();
try{
MyClass o=(MyClass)hack.clone();
o.display();
}
catch(CloneNotSupportedException e){
e.printStackTrace();
}
}
}