漏洞攻擊
分析使用環境變數來儲存機密的潛在危險
儘管 DevOps 人員經常使用環境變數來儲存應用程式中的機密,但正如趨勢科技分析所指出,這些變數會讓網路駭客很容易從事惡意活動。
DevOps 人員經常透過環境變數來存取組態設定,這樣的作法在容器環境中尤其方便:因為使用環境變數來傳遞組態設定較為容易。但是,從雲端資安 的角度來看,使用環境變數來傳遞機密的作法應盡量避免,同時也應受到更多討論。因為,這麼做雖然比較容易,但卻可能有危險,萬一環境變數中的機密遭到外流,很可能會引發資安事件。
什麼是環境變數?
此處所指的環境是像指令列介面或子介面執行時的環境,而環境變數則是這個環境當中使用的機碼/數值。定義環境變數的方式有很多,其中一種就是使用「export」全域指令,這個指令經常用在指令列腳本中。此外,在 Linux 作業系統上啟動容器化應用程式時可使用「-e」參數來設定環境變數。還有,在建構容器映像時也可以在 Dockerfile 中使用「ENV」指令來設定執行時期的環境變數。環境變數在所屬環境當中是以明碼方式存在,並無加密。
這些定義在技術上的意義為何?首先我們要釐清環境變數的有效範圍。以指令列腳本 (圖 2) 的情況為例,其環境變數的有效範圍是指令列腳本或執行環境與其子處理程序。在容器的情況中,環境變數的有效範圍是容器處理程序與其子處理程序。換句話說,環境變數會被複製到每個子處理程序當中。
在技術細節上,這些變數會先複製到處理程序的堆疊記憶體中,然後再複製到新的子處理程序內。換句話說,環境變數會在下列情況時複製到新的處理程序中:
當執行一個外包裝應用程式 (wrapper application) 時。
啟動一個腳本,該腳本使用環境變數來指定一些組態設定,然後啟動一些應用程式,這些應用程式不一定會用到組態設定的所有欄位。
為何使用環境變數來儲存機密不是一種好的作法?
之前寫過一篇文章指出良好的機密管理有多重要,以及不當的作法如何讓駭客有機會進入關鍵系統,還有機密外洩如何導致供應鏈遭到入侵。那麼,理想的機密管理該如何做?以下是我們提出的幾點建議:
- 加密保存:使用另一個密碼來保護登入憑證與機密。
- 使用安全的管道來傳輸:用來移動或傳輸機密的管道必須做好防護措施以防止被人攔截或外洩。
- 機密要定期更換:資料庫和服務應每隔一段時間就更換新的登入憑證。
- 縮短可用期間:原則上,機密應該只能短暫存在於記憶體中,用完之後就立刻清除記憶體。
如果我們認同以上四點對於機密的安全有重大的影響,那麼,使用環境變數來存放機密就違反了第四點 (縮短可用期間)。縮短可用期間的意思是指機密只能暫時存在於記憶體中,用完就要立刻清除。這就好像作業系統應防止一個處理程序的機密意外出現在另一個處理程序未初始化的記憶體中一樣。
情況有多嚴重?
為了示範,我們針對環境本身進行分析,並在一個容器中執行 MySQL 資料庫,我們發現,儲存系統管理 (root) 密碼的環境變數外洩的情況要比機密 (系統管理密碼) 本身遭到存取來得嚴重。
不過,當在某個雲端服務供應商 (CSP) 的預設服務當中執行無伺服器功能 (經由事件或觸發動作,如:存取端點、資料庫或訊息佇列),而該服務含有敏感的環境變數時,這個執行動作就可能因為記憶體讀取漏洞而導致整個服務遭到入侵,或讓駭客從遠端執行程式碼 (RCE)。正如我們先前發表的文章所說,最嚴重的情況有可能讓駭客上傳他們想要執行的程式碼。
使用環境變數來儲存機密的潛在危險是,架構上的解決方案可能讓使用者不小心跨越了安全邊界,甚至只是某一項資訊遭到外洩。而且由於環境變數會複製到每一個子處理程序,因此外洩的可能性也會增加。所以,凡是會以子處理程序啟動其他程式的應用程式,風險就會更高。
DevOps 團隊之所以會使用環境變數來儲存機密,有可能是設計應用程式時對環境變數的屬性不甚了解,但也可能是沿用以往的慣例。正因如此,開發人員在設計產品時,應該要徹底了解環境變數的屬性及可能帶來的影響。但最好的作法就是:完全不使用環境變數來儲存機密。
雲端環境變數中的機密
在研究雲端服務與監控某起 事件時,我們的團隊注意到有的 CSP 在其授權程序的某些階段也會使用環境變數來儲存機密。為了保障其服務安全,我們已經將這些問題通報給 CSP 並決定不公布這些 CSP 的名單。
當開發人員需要執行指令列介面 (CLI) 工具時,甚至是使用 Visual Studio Code 這類開發平台的擴充功能時,開發人員要先執行初始化設定流程。此時會需要提供密碼或金鑰來存取 CSP 服務,而授權金鑰可使用兩種方式來儲存:使用本地端檔案 (絕大多數以明碼儲存),或使用環境變數。
當我們的團隊開始研究無伺服器服務時,我們發現開發人員電腦上的環境變數也會出現在無伺服器執行環境當中。正如我們 2019 年的報告指出,這些環境中存在的機密有可能在不同情況下遭到濫用,如果駭客有辦法在無伺服器環境內下載 CSP 官方的 CLI 工具,就能取得這些服務經由這些機密提供的授權與權限。
有鑑於透過這種方式來取得敏感資料相當容易,我們預測雲端、通訊管道與工具將成為網路犯罪集團的攻擊目標。像這樣的入侵事件,我們至少已經看過兩起案例。第一起案例是 TeamTNT 駭客集團利用敏感的環境變數來入侵雲端環境。另一起較近期的案例是 供應鏈攻擊事件,駭客利用修改過的 Python 函式庫來蒐集敏感的環境變數。
使用環境變數來儲存機密的情況有多普遍?
針對這個問題,我們不可能取得所有的程式碼來進行徹底的分析,所以只能根據一些估計來了解這樣的作法到底有多普遍。不過,許多開發人員都認為使用環境變數來儲存機密是一種「處理私密金鑰/密碼最安全的方式」,如圖 9 所示。
我們認為使用保險箱 (vault) 而非環境變數來儲存機密才是更好的作法。此外,我們也建議唯有在需要用到時才讀取機密,然後要透過安全、加密的管道來取得,機密用完之後就應立刻清除記憶體。這麼做可以讓機密只存在於應用程式本身的處理程序當中,不會意外擴散到子處理程序內,進而減少機密外洩的風險。
環境變數與漏洞
所幸,並非所有人都認為環境變數是儲存機密最安全的地方。不過由於我們在研究各種軟體產品與 CSP 時看到了一些實際案例,所以這問題看來並未受到重視,而且有可能是承襲一些開放原始碼軟體的作法。
結論
在應用程式功能和資料當中使用環境變數原本是一種安全、快速、有效率的開發與部署方法。但環境變數不應用來儲存可能導致駭客攻擊的敏感資料或機密,例如:登入憑證、存取金鑰、登入網址,以及連線指令。儘管 DevOps 社群認為這是一種常見的作法,但根據過去發生的資安事件顯示,這類作法可能遭到濫用,長期下來也可能對企業資安帶來負面影響。
我們一再強調開發人員應了解使用環境變數來儲存機密的後果。我們也在一些先前發表的文章當中提出了更安全的作法與建議:
最理想的狀況就是:完全使用環境變數來儲存機密,因為這麼做會增加某些應用程式遭受攻擊的管道。不論專案大小,也不論專案是由哪個團隊負責,企業都有更安全的方法來管理機密。DevOps 人員與開發人員應謹記一件事:縱然系統不可能達到百分之百的安全,但還是有一些工具可以將風險降至最低,不讓駭客有更多管道可攻擊應用程式。以下是一些有助於降低這類風險的資安最佳實務原則:
- 遵從 CSP 的建議來保護環境變數和專案 (請參考相關文件)。
- 使用保險箱 (vault) 來儲存金鑰和密碼。這或許會為開發團隊或企業帶來一些額外成本,但卻可以讓使用者和資安團隊多一層保障來確保登入憑證安全。
- 使用客製化容器映像。使用預設的服務雖然可以讓部署或開發工作更快、更有效率,但客製化容器映像不論在設計和實作上都讓開發人員有更多改善功能與安全的空間。
- 使用加密通道與管道。將變數的內容加密可確保敏感資訊 (如密碼和 ID) 即使遭到不當存取也不會洩密。
原文出處:Analyzing the Hidden Danger of Environment Variables for Keeping Secrets