原文連結
這是迄今為止第一個讓我覺得後怕的攻擊方式,涉及的範圍廣難以防禦,攻擊效果立竿見影。大量的網站和Web介面都未做Hash碰撞攻擊的防禦,一拿一個準。
隨著RESTful風格的介面普及,程式設計師預設都會使用json作為資料傳遞的方式。 json格式的資料冗餘少,相容性高,從提出到現在已被廣泛的使用,可以說成為了Web的一種標準。無論我們服務端使用什麼語言,我們拿到json格式的資料之後都需要做jsonDecode(),將json字串轉換為json對象,而對象預設會儲存於Hash Table,而Hash Table很容易被碰撞攻擊。我只要將攻擊資料放在json中,服務端程式在做jsonDecode()時必定中招,中招後CPU會立刻飆升至100%。 16核心的CPU,16個請求就能達到DoS的目的。
所有測試程式都在Mac Pro下進行,為了測試方便我只建構了65536條json鍵值對,真正發動攻擊時可以建構數十萬甚至百萬千萬的資料。
攻擊資料我已經轉換為json格式
#Hash攻擊json資料
普通json資料
Java版本Hash攻擊資料
#一. JavaScript測試
//只需要一行代码就能看到效果var jsonSrc = '这里输入json数据';
我們只需要在js中輸入一行程式碼就能看到效果,一般資料和Hash攻擊資料都是65536行鍵值對。我本地測試的效果如下:
透過Chrome自帶的任務管理器可以看出CPU馬上升到100%,將近1分鐘才執行完成,而普通的資料幾毫秒就能執行完成;
二. PHP測試
$json = file_get_contents("https://raw.githubusercontent.com/laynefyc/php_thread_demo/master/hashNomal.json"); $startTime = microtime(true); $arr = json_decode($json,true); $endTime = microtime(true); echo "Nomal:".($endTime - $startTime)."\r\n"; $json = file_get_contents("https://raw.githubusercontent.com/laynefyc/php_thread_demo/master/hash.json"); $startTime = microtime(true); $arr = json_decode($json,true); $endTime = microtime(true); echo "Attack:".($endTime - $startTime)."\r\n";
PHP中我們透過file_get_contents遠端去拿數據,運行對比時間,相差10多秒,php-fpm單一進程佔用CPU 100%。
三. Java測試
public String index(){String jsonStr = "";try { FileReader fr = new FileReader("t.log");//需要读取的文件路径BufferedReader br = new BufferedReader(fr); jsonStr = br.readLine(); br.close(); fr.close(); //关闭文件流 }catch(IOException e) { System.out.println("指定文件不存在");//处理异常 } Map<String, Object> map = new HashMap<String, Object>();map = JSONObject.fromObject(jsonStr);return "Hash Collision ~"; }
Java中我們透過讀取檔案的方式做測試,Java的Hash演算法與PHP和JavaScript有略微的差別,但是大同小異,我們同樣構造了6萬行簡單的數據。 Spring boot框架中瀏覽器發起一次訪問,26秒之後才返回結果,期間CPU被打滿。
四. 其他語言還在研究中…
HashTable是很通用的資料結構,資料結構與演算法上專門有一堂課來說它,所以Hash Collision是普遍存在的,各語言在實作上只是散列演算法和Table儲存上有細微差別。
為了驗證Java的Hash碰撞攻擊也生效,我整個端午假期都在看Java HashTable相關的文章,經過努力最後還是成功的生成了攻擊資料。過程非常不簡單,這也驗證了一個想法--所有高個上的東西最後分解出來都是基礎的資料結構知識。
幾年前PHP的版本還是5.2,我們可以把所有的Hash Key都放在POST請求的Body中,例如:
Post Data: k1=0&k2=0&k3=0...k999998=0&k999999=0
服務端拿到資料後會將所有參數儲存到Hash Table ($_POST)中,透過這種方式能很方便的實現攻擊。但現在這種方式行不通了,因為我們很容易就能在Nginx層和PHP層限制Http請求的參數個數和大小。 PHP預設只允許1000個參數,這個量級對伺服器完全沒影響。
現在是2017年,json格式和RESTful風格的介面已經非常流行。帶給我們便捷編碼的同時,也為Hash Collision Dos提供了新的方式。現在很多RESTful風格的介面如下:
Data: {"action":"create-account","data":""}
如上接口,我們直接把攻擊的資料放入data參數中,服務端接收到資料後肯定會做jsonDecode(),很方便的就達到了攻擊的目的。
要想防禦Hash Collision Dos攻擊,業界已經有很多成熟的方案了,不過都是建議換語言或重寫HashTable。這裡只說當前json格式解析的問題。首先我們要增加權限驗證,最大可能的在jsonDecode()之前把非法使用者拒絕。其次在jsonDecode()之前做資料大小與參數白名單驗證。舊專案的改造與維護成本如果很高,建議自己重寫jsonDecode()方法
以上是一種進階的DoS攻擊-Hash碰撞攻擊的詳細內容。更多資訊請關注PHP中文網其他相關文章!