天天看點

《Java編碼指南:編寫安全可靠程式的75條建議》—— 指南15:不要依賴可以被不可信代碼覆寫的方法

本節書摘來異步社群《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");