這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。IPv4 掃描暴露出的 `net/http/pprof` 端點(endpoint)原文發表日期: 2017/9/27Go語言的 [net/http/pprof](https://golang.org/pkg/net/http/pprof/) 包是令人難以置信的強大的,調試正在啟動並執行生產伺服器的這個功能微不足道,而在這個調試過程,就很容易不經意間將調試資訊暴露給世界。在這篇文章中,我們用 [zmap project](https://github.com/zmap) 作為例子,展示一個現實中真正的問題,並且說明你可以採取的預防措施。> 早期版本提出,暴露的端點可能泄露原始碼。[Aram Hăvărneanu 指出了這個錯誤](https://github.com/golang/go/issues/22085#issuecomment-333166626),本文已修正。## 引言通過一個 `import _ "net/http/pprof"` ,你可以將分析端點添加到 HTTP 伺服器。```gopackage mainimport ("fmt""log""net/http"_ "net/http/pprof" // here be dragons)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})log.Fatal(http.ListenAndServe(":8080", nil))}```這個服務不僅會對你說 `Hello World!`,它還會通過uri路徑 `/debug/pprof` 返回診斷報告。- `/debug/pprof/profile`: 30秒的CPU狀態資訊- `/debug/pprof/heap`: 記憶體的堆資訊- `/debug/pprof/goroutine?debug=1`: 所有協程的堆棧蹤跡- `/debug/pprof/trace`: 執行的追蹤資訊舉個例子,假如我們使用 [hey](https://github.com/rakyll/hey) (負載測試工具)給這個服務增加一些負載,同時我們查看下堆棧資訊,如下```shell$ wget -O trace.out http://localhost:8080/debug/pprof/trace$ go tool trace trace.out```在幾秒鐘內,我們以較細的顆粒度地檢查伺服器此功能對於追蹤僅在生產環境中出現的錯誤和效能問題非常重要。但是,許可權越大則責任越大。## 開啟 Pprof 服務這種機制非常簡單,他只需一次 import ! 它可以在任何的地方 import,甚至在你使用的 library 中。當你興奮地使用它來追蹤你的協程泄露問題時,你或許會忘記事後移除這個調試入口。這就導致了問題:有多少 pprof 服務暴露在網路中?為了回答這個問題,我們可以嘗試在 IPv4 掃描開啟 pprof 的伺服器。為了限制搜尋範圍,我們可以選擇一些合理的連接埠。- 6060 官方文檔建議的- 8080 經常在入門教程出現- 80 標準的 HTTP 連接埠- 443 HTTPS 的連接埠接下來讓你失望了,因為收到雲端服務器的警告郵件,所以作者沒有完成這個搜尋工作。儘管我可以用更狡猾的方法來完成這個工作,但是我已經有足夠的證據說服自己這個問題在現實中是真實存在的。[zmap project](https://github.com/zmap) 用一行命令就可以進行這些類型的掃描```sh$ zmap -p 6060 | zgrab --port 6060 --http="/debug/pprof/"```[zmap](https://github.com/zmap/zmap) 掃描 IPv4 範圍中開啟6060連接埠的服務並調用它,然後 `banner grabber` 的 [zgrab](https://github.com/zmap/zgrab) 採集 HTTP 要求的 `GET /debug pprof` 的響應結果與問題。我們可以認為任意響應為 `200 OK` 的伺服器與包含 `goroutine` 的響應體即為命中。下面是我們發現的內容:- 至少有 69 個 IP 使用 `pprof` 開啟了 6060 連接埠- 同上,至少有 70 個 IP 開啟了 8080 連接埠- 在掃描 80 連接埠之前, [Google Cloud](https://cloud.google.com/) 懷疑我的伺服器被入侵成為挖礦機(mining cryptocurrency)而停止了我的帳號.好吧,這個"挖礦"部分有點怪異,不過打住。現在我們知道了有許多機器在公網上開放了 `pprof` 服務,這正是我強調的問題。我根據 WHOIS 資訊向伺服器所有者發送了郵件報告問題。我不得不說來自 [linode](https://www.linode.com/) 的回應非常快速積極。我很想看到更有才華的人可以完成這個全網掃描,我懷疑還有更多的伺服器在 80 連接埠與 443 連接埠暴露了 pprof 服務。## 風險安全問題:- 顯示函數名與檔案路徑- 分析資料可能揭示商業敏感資訊(例如,web服務的流量)- 分析會降低效能,為 DoS 攻擊增加助攻## 預防Farsight Security [警告過這個問題,並且提供了建議](https://www.farsightsecurity.com/2016/10/28/cmikk-go-remote-profiling/) > 一個簡單而有效方式是將pprof http伺服器放在本地主機上的一個單獨的連接埠上,與應用程式http伺服器分開。總之,你需要安排兩台HTTP伺服器。常見的設定是- 應用程式服務將80連接埠暴露在公網上- `pprof`服務監聽本地6060連接埠並且限於本地訪問原生的寫法是不使用全域的 HTTP 方法的情況下構建主應用程式(使用隱藏配置 `http.DefaultServeMux` ),而是用標準的方法啟動你的 pprof 服務。```go// Pprof server.go func() {log.Fatal(http.ListenAndServe("localhost:8081", nil))}()// Application server.mux := http.NewServeMux()mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})log.Fatal(http.ListenAndServe(":8080", mux))```如果處於任何原因,你都需要將全域 `http.DefaultServeMux` 用於你的應用伺服器,你可以切換它然後像往常執行。```go// Save pprof handlers first.pprofMux := http.DefaultServeMuxhttp.DefaultServeMux = http.NewServeMux()// Pprof server.go func() {log.Fatal(http.ListenAndServe("localhost:8081", pprofMux))}()// Application server.http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})log.Fatal(http.ListenAndServe(":8080", nil))```我封裝了一個 [professor package](https://github.com/mmcloughlin/professor),通過它來使用 `net/http/pprof` 包,並且提供一些便利的方法。```go// Pprof server.professor.Launch("localhost:8081")// Application server.http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})log.Fatal(http.ListenAndServe(":8080", nil))```## 結論`net/http/pprof` 是很強大,但是請不要讓你的調試資訊暴露給全世界,遵循以上預防措施,你會沒事的。
via: http://mmcloughlin.com/posts/your-pprof-is-showing
作者:mmcloughlin 譯者:lightfish-zhang 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
432 次點擊 ∙ 1 贊