java安全編碼指南之:敏感類的複製

只愛宅zmy發表於2020-09-28
簡介
一般來說class中如果包含了私有的或者敏感的資料的時候是不允許被複製的。
如果一個class不想被複製,我們是不是不提供複製的方法就能保證class的安全了呢?
一起來看看吧。
一個簡單的SensitiveObject
假如我們有下面的一個SensitiveObject,它的作用就是儲存一個password,並且提供了一個修改password的方法:
public class SensitiveObject1 {
private char[] password;
SensitiveObject1(String iniValue){
    this.password = iniValue.toCharArray();
}
public final String get() {
    return String.valueOf(password);
}
public final void doPasswordChange(){
    for(int i = 0; i < password.length; i++) {
        password[i]= '*' ;}
}
public final void printValue(){
    System.out.println(String.valueOf(password));
}
}
看上去沒什麼問題,如果我們希望密碼被返回之後就不能夠被修改,應該怎麼做呢?
SensitiveObject的限制
為了實現上面的功能,我們可以考慮引入一個是否返回的變數,如果返回過了,就不允許進行密碼修改了。
那麼我們可以將上面的程式碼修改成這樣:
public class SensitiveObject2 {
private char[] password;
private boolean returned=false;
SensitiveObject2(String iniValue){
    this.password = iniValue.toCharArray();
}
public final String get()
{
    if(!returned) {
        returned=true;
        return String.valueOf(password);
    }else {
    throw new IllegalStateException("已經返回過了,無法重複返回");
    }
}
public final void doPasswordChange(){
    if(!returned) {
        for (int i = 0; i < password.length; i++) {
            password[i] = '*';
        }
    }
}
}
透過加入了returned標籤,我們可以控doPasswordChange方法,只能在未返回之前進行密碼修改。
我們看下呼叫程式碼:
    SensitiveObject2 sensitiveObject2= new SensitiveObject2(");
    sensitiveObject2.doPasswordEncrypt();
    System.out.println(sensitiveObject2.get());
對SensitiveObject的攻擊
怎麼對上述程式碼進行攻擊呢?
如果我們想在密碼返回之後仍然對密碼進行修改,怎麼做到呢?
如果SensitiveObject2可以複製,我們是不是就能夠儲存一份char[]和boolean的副本了呢?
因為char[]屬於引用複製,所以在複製的副本里面對char[]進行修改完全可以影響到原SensitiveObject2的內容。
但是,雖然clone方法是定義在Object中的,如果子類沒有實現Cloneable介面的話,將會丟擲CloneNotSupportedException異常。
考慮到SensitiveObject2不是一個final的類,我們可以透過繼承SensitiveObject2來實現目的:
public class MaliciousSubSensitiveObject extends SensitiveObject2 implements Cloneable{
MaliciousSubSensitiveObject(String iniValue) {
super(iniValue);
}
public MaliciousSubSensitiveObject clone(){
    MaliciousSubSensitiveObject s = null;
    try {
        s = (MaliciousSubSensitiveObject)super.clone();
    } catch(Exception e) {
        System.out.println("not cloneable");
    }
    return s;
}
public static void main(String[] args) {
    MaliciousSubSensitiveObject object1 = new MaliciousSubSensitiveObject(");
    MaliciousSubSensitiveObject object2 = object1.clone();
    String password1= object1.get();
    System.out.println(password1);
    object2.doPasswordChange();
    object1.printValue();
}
}
可以看到,雖然object1先返回了password,但是這個password被clone過的object2進行了修改,最終導致object1中的password值發生了變化。
解決辦法
怎麼解決呢?
一個簡單的方法就是將SensitiveObject class定義為final,這樣就不能繼承,從而避免了上訴問題。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983372/viewspace-2724707/,如需轉載,請註明出處,否則將追究法律責任。

相關文章