本節書摘來異步社群《java編碼指南:編寫安全可靠程式的75條建議》一書中的第1章,第1.15節,作者:【美】fred long(弗雷德•朗), dhruv mohindra(德魯•莫欣達), robert c.seacord(羅伯特 c.西科德), dean f.sutherland(迪恩 f.薩瑟蘭), david svoboda(大衛•斯沃博達),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
不可信代碼可以濫用可信代碼提供的api來覆寫一些方法,如object.equals()、object. hashcode()和thread.run()。這些方法是很重要的目标,因為它們通常是在幕後被使用,很可能以不容易辨識的方式與其他元件進行互動。
通過提供覆寫的實作,攻擊者可以使用不可信的代碼來收集敏感資訊、運作任意代碼,或者發起拒絕服務攻擊。
關于覆寫object.clone()方法的更多詳細資訊參見指南10。
下面的違規代碼示例展示了一個licensemanager類,它維持着一個licensemap。這個映射存儲的是許可證類型(licensetype)和許可證值對。
public class craftedlicensetype extends licensetype {
private static int guessedhashcode = 0;
@override
public int hashcode() {
// returns a new hashcode to test every time get() is called
guessedhashcode++;
return guessedhashcode;
}
public boolean equals(object arg) {
// always returns true
return true;
}<code>`</code>
下面是惡意的用戶端程式:
public class licensemanager {
map licensemap =
new identityhashmap();
// ...
根據java api中identityhashmap類的文檔[api 2006]:
這個類以一個散清單實作map(映射)接口,在比較鍵(和值)時使用引用相等代替對象相等。換句話說,如果在一個identityhashmap中有k1和k2兩個鍵,那麼當且僅當(k1==k2)時,才可以說它們是相等的。(而對于普通的map實作(如hashmap)中的兩個鍵k1和k2,當且僅當(k1==null ? k2==null : k1.equals(k2))時,才可以說它們是相等的。)
是以,覆寫方法不能暴露内部類的細節。用戶端程式可以繼續添加許可證密鑰,甚至可以檢索添加的鍵值對,如下列用戶端代碼所示。
final class licensetype {
下面的違規代碼示例包含一個widget類和一個含有一組部件的layoutmanager類。
public class navigator extends widget {
public navigator(int noofcomponents) {
super(noofcomponents);
int res = 31;
res = res * 17;
return res;
用戶端代碼如下:
public final class widget {
在下面的違規代碼示例中,worker類及其子類subworker,均包含一個用來啟動一個線程的startthread()方法。
worker w = new subworker();
w.startthread("thread");<code>`</code>
用戶端可能會希望parent和child都被列印出來。然而,child會被列印兩次,因為被覆寫的方法run()在啟動一個新線程時被調用了兩次。
下面的合規解決方案修改了subworkder類,移除了對super.startthread()的調用。
worker w1 = new worker();
w1.startthread("parent-thread");
worker w2 = new subworker();
w2.startthread("child-thread");