作為一名安全研究人員,我需要定期對大量的目標主機進行安全掃描。最近,我遇到了一個挑戰(zhàn):需要在短時間內向250萬臺主機發(fā)送5億次非RFC標準的HTTP/1.1請求,理想情況下是在幾個小時內完成。經(jīng)過一番研究和實踐,我成功地使用Go語言構建了一個高效的“HTTP大炮”,并成功完成了任務。
在眾多編程語言中,我最終選擇了Go語言作為實現(xiàn)工具,主要原因有三點:
當然,我也嘗試過使用Rust語言來實現(xiàn),但異步tokio類型的復雜性讓我望而卻步。相比之下,Go語言的并發(fā)模型更加直觀易懂,即使是JS開發(fā)者也能輕松駕馭。
你可能會問,5億次HTTP/1.1請求到底意味著什么?這是一個很大的數(shù)字嗎?答案是肯定的。
如果使用curl命令逐個發(fā)送這些請求,即使每秒發(fā)送2個請求,也需要7.9年才能完成。在實際情況下,由于服務器的速率限制和網(wǎng)絡延遲,所需時間會更長。
從數(shù)據(jù)傳輸?shù)慕嵌葋砜矗?億次HTTP/1.1請求的數(shù)據(jù)量并不算太大:
真正的挑戰(zhàn)在于如何高效地建立連接、發(fā)送請求和處理響應。
雖然在代碼層面,發(fā)送一個HTTP/1.1請求只需要簡單的幾行代碼,例如:
resp, err := http.Get("https://example.com")但在底層,HTTP庫需要執(zhí)行一系列操作:
需要注意的是,上述任何一個步驟都可能失敗,因此需要進行錯誤處理和重試。
為了提高發(fā)送效率,我們需要盡可能地減少每個請求的耗時。通過分析單個HTTP請求的步驟,我們可以找到優(yōu)化的方向:
基于上述優(yōu)化思路,我設計了一個多級流水線式的HTTP請求發(fā)送器,主要包括三個模塊:
為了提高內存利用率和減少對象創(chuàng)建的開銷,我使用了對象池來管理HTTP連接和請求/響應對象。同時,為了避免單個目標服務器過載,我對每個目標服務器的請求頻率進行了限制。
為了追求極致的性能,我選擇了fasthttp庫來替代Go語言標準庫中的net/http。fasthttp是一個輕量級、高性能的HTTP庫,經(jīng)過 benchmark 測試,其速度比net/http快了將近10倍。
為了跳過DNS解析步驟,我自定義了一個Dial函數(shù),直接使用預先解析好的IP地址建立TCP連接。
req.SetDial(func(addr string) (net.Conn, error) { return customDialer.Dial(resolved_ip)})由于我發(fā)送的是手工構造的非RFC標準HTTP請求,因此可以禁用fasthttp庫中的請求標準化功能,進一步提高性能。
req := rawfasthttp.AcquireRequest()resp := rawfasthttp.AcquireResponse()rawBytes := []byte("GET / HTTP/1.1/r/nHost: example.com/r/n/r/n")req.SetRequestRaw(rawBytes)err := client.Do(req, resp)為了進一步提高發(fā)送效率,我將HTTP請求發(fā)送器部署到了DigitalOcean的Kubernetes集群中。DigitalOcean提供了每月2TB的免費流量,足以滿足我的測試需求。
為了實現(xiàn)自動化的彈性伸縮,我編寫了一個簡單的JavaScript腳本,根據(jù)任務隊列的長度動態(tài)調整Kubernetes Deployment的副本數(shù)量。
在測試過程中,我遇到了一些挑戰(zhàn),例如:
最終,我成功地構建了一個高效的HTTP請求發(fā)送器,并在幾個小時內完成了向250萬臺主機發(fā)送5億次HTTP/1.1請求的任務。
通過這次實踐,我深刻體會到了Go語言在網(wǎng)絡編程方面的強大能力,也學習到了很多關于HTTP協(xié)議和網(wǎng)絡安全的知識。我相信,這些經(jīng)驗將會對我未來的安全研究工作有所幫助。
本文鏈接:http://m.www897cc.com/showinfo-26-99168-0.htmlGo語言助力安全測試:24小時內發(fā)送5億次HTTP/1.1請求
聲明:本網(wǎng)頁內容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 我們一起聊聊審核平臺前端新老倉庫遷移