1. 程式人生 > >java安全編碼指南之:敏感類的拷貝

java安全編碼指南之:敏感類的拷貝

[toc] # 簡介 一般來說class中如果包含了私有的或者敏感的資料的時候是不允許被拷貝的。 如果一個class不想被拷貝,我們是不是不提供拷貝的方法就能保證class的安全了呢? 一起來看看吧。 # 一個簡單的SensitiveObject 假如我們有下面的一個SensitiveObject,它的作用就是儲存一個password,並且提供了一個修改password的方法: ~~~java 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的限制 為了實現上面的功能,我們可以考慮引入一個是否返回的變數,如果返回過了,就不允許進行密碼修改了。 那麼我們可以將上面的程式碼修改成這樣: ~~~java 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方法,只能在未返回之前進行密碼修改。 我們看下呼叫程式碼: ~~~java SensitiveObject2 sensitiveObject2= new SensitiveObject2("www.flydean.com"); sensitiveObject2.doPasswordEncrypt(); System.out.println(sensitiveObject2.get()); ~~~ # 對SensitiveObject的攻擊 怎麼對上述程式碼進行攻擊呢? 如果我們想在密碼返回之後仍然對密碼進行修改,怎麼做到呢? 如果SensitiveObject2可以拷貝,我們是不是就能夠儲存一份char[]和boolean的副本了呢? 因為char[]屬於引用拷貝,所以在拷貝的副本里面對char[]進行修改完全可以影響到原SensitiveObject2的內容。 但是,雖然clone方法是定義在Object中的,如果子類沒有實現Cloneable介面的話,將會丟擲CloneNotSupportedException異常。 考慮到SensitiveObject2不是一個final的類,我們可以通過繼承SensitiveObject2來實現目的: ~~~java 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("www.flydean.com"); 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,這樣就不能繼承,從而避免了上訴問題。 本文的例子: [learn-java-base-9-to-20/tree/master/security](https://github.com/ddean2009/learn-java-base-9-to-20/tree/master/security) > 本文已收錄於 [http://www.flydean.com/java-security-code-line-object-copy/](http://www.flydean.com/java-security-code-line-object-copy/) > > 最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現! > > 歡迎關注我的公眾號:「程式那些事」,懂技術,更