網站安全🔒 伺服器端請求偽造 SSRF 攻擊 — 「項莊舞劍,意在沛公」

Jayden Lin
Dec 30, 2020 · 11 min read

筆者任職 Yahoo ,《經典駭客攻擊教程:給每個人的網站安全入門》線上課程講師 ,粉絲團《程式猿吃香蕉🍌》

鴻門宴的故事相信很多人都聽過,其中「項莊舞劍,意在沛公」更是一段著名的橋段,由於「伺服器端請求偽造」的攻擊概念較為複雜,我們將用這個概念來講解「伺服器請求偽造」的攻擊原理,除了幫助大家更易於理解之外,也能增添一些趣味性。

「伺服器端請求偽造」英文全名為 Server Side Request Forgery ,簡稱 SSRF ,是較為複雜一些的網站攻擊手段,駭客必須先收集部分的資訊 (例如:內部使用的 API ) 才能達成攻擊。但這並不表示這類的攻擊不容易發生,反而隨著許多第三方 Open API 的流行與廣泛於企業內使用 (例如:Google API、Facebook API、AWS API 等等),只要程式碼一不注意,駭客就可以使用伺服器請求偽造 SSRF ,穿透內網 (Intranet) 達成攻擊。是的,你沒有看錯,如果你的程式碼有伺服器端請求偽造 ( SSRF )漏洞,駭客是可以無視於內網的防護的。

本文將會介紹伺服器端請求偽造 ( SSRF ) 的攻擊原理,也會舉實際的程式碼範例說明攻擊手法,最後會說明防禦 SSRF 的注意事項。

本篇內容:
✔ 伺服器請求偽造攻擊原理 - 項莊舞劍,意在沛公
✔ 實際攻擊範例:心情留言板網站為例
✔ 防禦的重點注意事項

▍伺服器端請求偽造 SSRF 攻擊原理

如圖所示,「伺服器端請求偽造」是駭客從「客戶端」,做了一個「偽造請求」給伺服器端,注意!這裡的伺服器端有兩台不同的機器,一台是「中介伺服器端」,另一台是「內部受保護的伺服器端」,其中「內部受保護伺服器端」處於內網,並無對外的接口,需要透過「中介伺服器端」與外網的「客戶端」聯繫。

而這個「偽造請求」之所以被稱為「偽造請求」,是因為這個請求不是要給原本對接的「中介伺服器端」的,而是針對後面「內部受保護的伺服器端」( 攻擊目標 ) 所做的請求,有點「項莊舞劍,意在沛公」的意思。

為了使大家容易理解,我們以這個歷史故事來解釋伺服器端請求偽造 ( SSRF ) ,相信大家都聽過鴻門宴的故事:項羽宴請劉邦,范增密謀讓項莊在宴會上直接刺殺劉邦。

如下圖所示,我們假設「客戶端」是項莊,也就是駭客的角色,「中介伺服器端」是項羽,「內部受保護的伺服器端」是劉邦,項莊 (駭客) 提議要舞劍,而「舞劍」其實是針對劉邦的的一個「偽造請求」,當這個請求傳送給項羽「中介伺服器端」時,項羽不疑有他,允許了「舞劍」這個「偽造請求」,並讓劉邦「內部受保護的伺服器端」也接受了這個舞劍的「偽造請求」,從某個角度來說,這也讓項羽變成了一個「跳板」去刺殺劉邦。

注意這裡的幾個角色關係,可以幫助你理解「伺服器請求偽造 SSRF」的原理:

  • 「偽造請求」的傳送目標是「內部受保護的伺服器端」:

這個請求 (可以是 JSON 或是 XML 等格式) 是被包裝成「中介伺服器端」可接收的格式,但他實際的目的,是要被「內部受保護的伺服器端」(攻擊目標) 給存取,因此它也要同時符合「內部受保護的伺服器端」所能接收的格式。

如同項莊舞劍這個請求,舞劍請求可以同時被項羽接收,也可以同時被劉邦接收 (被刺殺),但舞劍這個請求並不是要娛樂項羽,他的目的是刺殺背後的劉邦。

  • 「中介伺服器端」本身並不知道這個「偽造請求」會傷害「內部受保護的伺服器端」

「中介伺服器端」是無意間被當成一個「跳板」,將「偽造請求」送去傷害「內部受保護的伺服器端」,真正做壞事的人是來自客戶端的駭客。如同項羽並非有意要殺劉邦,他一開始也不知道同意了舞劍這個請求會傷害劉邦,真正的壞人是項莊 (當然歷史上項羽當時的真實想法沒人知道,這裡假定照史書所說,項羽不聽范增的勸,無意要殺劉邦)。

了解攻擊的原理之後,那麼實作這項攻擊的重點就在於:

1) 如何做出一個「偽造請求」,駭客怎麼知道「內部受保護的伺服器端」要接收什麼格式?

2) 要怎麼突破「中介伺服器端」讓它將「偽造請求」往後傳遞?

我將依序說明這兩個問題:

1. 如何做出一個偽造請求?

其實隨著第三方 Open API 的流行語企業的廣泛採用,「內部受保護的伺服器端」很有可能是去呼叫 Google API、Facebook API、AWS API 、Apple API 等等第三方 Open API (如下圖所示),而這些 API 的介面定義 (包含 endpoint 跟 payload ),都可以在公開的官方文件裡面找到,因此要做出一個「偽造請求」來符合 API 的 endpoint 跟 paylaod 並不困難。

此外,「中介伺服器端」作為一個中介層,用來溝通「客戶端」跟「內部受保護的伺服器端」,而「中介伺服器端」與「內部受保護的伺服器端」之間的溝通,通常防護較弱。因為兩台伺服器是在內網 ( intranet ) 溝通,有些公司甚至對於這兩個伺服器之間的溝通完全不設防,沒有任何的權限驗證。

因此我才會說,「伺服器端請求偽造」是可以穿透內網的駭客攻擊,一旦偽造請求被往後傳送,後面很多時候是完全不設防的狀態。

2. 要怎麼突破「中介伺服器端」讓它將「偽造請求」往後傳遞?

接下來我們來談第二個問題,「偽造請求」怎麼突破「中介伺服器端」,最常見的方式是透過「目錄遍歷」 (Path Traversal ) 攻擊手法,詳細的方式可以參考我之前撰寫的這篇文章:

簡單來說,就是客戶端的偽造請求,可以透過「目錄遍歷」 (Path Traversal ) 攻擊手法,指定「中介伺服器端」要呼叫「內部受保護的伺服器端」的哪個 API 網址 ( endpoint ),我們接下來直接看實際案例怎麼做到。

▍伺服器請求偽造 SSRF 攻擊範例

假設一個情境,你經營一個心情留言板網站,後端的 API 介面如下:

新增留言:
POST http://internal.corp.com/${userId}/posts?message=${message}&token=${token}
管理者更新留言:
POST http://internal.corp.com/admin/posts/${postId}?message=${message}
  • 「新增留言 API」:有使用 token 驗證使用者身份,userId 為使用者的編號,token 為使用者的憑證,message 為留言內容。
  • 「管理者更新留言 API」 :為了便於管理留言,這一個 API 讓管理者可以快速更新惡意的留言內容,postId 為留言的編號。為了方便,這個 API 你沒有使用任何 token 驗證。此外,因為後端 API 是部署在內網,你以為很安全,覺得不會有外人可以存取得到「管理者更新留言」的 API。

然後,為了串接後端 API 跟前端頁面,你做了一個中介層,程式碼是這樣寫的:

整個架構如下圖所示:

這個中介層完全沒有暴露「管理者更新留言」的 API,而且 internal.corp.com 又在內網,所以你以為駭客無法存取到。

然而,這段程式碼是有目錄遍歷 ( Path Travesal ) 漏洞的,假設駭客想要惡意地更新別人的留言,若已知該留言的 postId 為 1234,駭客呼叫 /api/${userId}/posts 的時候,不是乖乖地傳送 userId 而是改傳送一個「偽造請求」:

admin%2Fposts%2F1234%3Fmessage%3Dhacked%26

注意!如我們在講述原理時提到,這個「偽造請求」可以同時滿足「中介伺服器端」以及「內部受保護的伺服器端」,並且這個「偽造請求」的目標是攻擊「內部受保護的伺服器端」。

這個字串是經過 URL 編碼 (encode) 之後的結果,目的是為了能通過 Express.js 程式碼app.post(`api/:userId/posts`) 對於 userId排除特殊字元的驗證。我們將它解碼 (decode) 後,其原本的字串為:

admin/posts/1234?message=hacked&

這個「偽造請求」通過了「中介伺服器端」往後傳送到了「內部受保護的伺服器端」(還記得「項莊舞劍,意在沛公」的故事嗎?),最終字串組合起來後 (如下圖所示):

結果變成了 :internal.corp/com/admin/posts/1234?message=hacked&

程式碼直接呼叫到內網的「管理者更新留言」API,又由於這個「管理者更新留言」的 API 沒有 token 保護,因此駭客可以直接達成攻擊的效果。

你可能會想,駭客怎麼會知道我內部的「管理者更新留言」API 怎麼設計?其實在 Restful API 盛行的今日,許多留言 API 的設計都大同小異 (見下圖 Facebook 新增 feed 的 API ),只要你的頁面有漏洞,駭客便有可能用暴力法不斷嘗試去「猜」你背後的程式碼邏輯,所以還是不要有僥倖的心理比較好。

▍伺服器端請求偽造 SSRF 防禦方式

伺服器端請求偽造 SSRF 的防禦重點在於:1) 如何阻擋偽造請求往後傳送 2) 如何避免偽造的請求生效。

以下提供幾項防禦重點:

  1. 避免目錄遍歷 ( Path Traversal ) 漏洞,減少「偽造請求」往後傳送的機會。
  2. 注意後端伺服器使用第三方/開源軟體服務的 API 權限設定,特別是適用 HTTP 請求的 Restful API ,例如:MongoDB 提供的 Restful API 或是 AWS 提供的 Restful API 等等。若沒有適當設定權限,當「偽造請求」穿透到內網的時候,可能會存取到機密資訊。
  3. 內部 API 最好還是要有憑證 (token) 保護,不能只有依賴內網的防火牆。
  4. 內部檔案要注意是否能使用 files:// 直接存取,如果是,要注意權限的設定,同樣不能只有依賴內網的防護。如果公司的內部檔案伺服器其權限是全公司通用沒有個別設定權限的,也應該要避免。

以上為伺服器端請求偽造 (SSRF) 的攻擊原理與防禦方式的介紹,希望對大家有幫助。對駭客與資訊安全有興趣的朋友,也可以參考我其他文章或是線上課程《經典駭客攻擊教程:給每個人的網站安全入門》:

若是喜歡我分享的內容,歡迎幫我按個拍手,可拍 50下,給我一點鼓勵,或是加入我的粉絲團《程式猿吃香蕉🍌》,一起分享軟體知識與心得!

程式猿吃香蕉

喜歡將軟體知識以簡單生動的方式講給你聽

程式猿吃香蕉

『來點更營養的軟體知識,吃香蕉吧!』我們是一群軟體開發愛好者,喜歡將軟體知識以簡單生動的方式講給你聽,順口好消化,營養又健康!

Jayden Lin

Written by

Yahoo 擔任 Lead Engineer,負責廣告系統,帶團隊做跨國開發。也是《程式猿吃香蕉》團隊創辦人,喜歡將實用的軟體知識以簡單生動的方式講給大家聽 😄😄😄

程式猿吃香蕉

『來點更營養的軟體知識,吃香蕉吧!』我們是一群軟體開發愛好者,喜歡將軟體知識以簡單生動的方式講給你聽,順口好消化,營養又健康!