本節書摘來自華章計算機《威脅模組化:設計和傳遞更安全的軟體》一書中的第2章,第2.4節,作者:[美] 亞當·斯塔克 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
建立清晰的軟體模型有助于尋找威脅,否則你會陷入到軟體功能正确與否的細節中。圖表是軟體模組化的最佳方法。
正如你在第1章學習到的内容,在白闆上繪制圖表是開始威脅模組化非常有效的方法,但是當一個系統特别複雜,在白闆上繪制或重新繪制模型就變得不可行了。這時,你要麼簡化系統要麼使用計算機化的方法。
本章,你能學習到各種圖表,在威脅模組化時如何使用各種圖表、如何處理大型系統威脅模組化的複雜性。你也能學到信任邊界、有效标簽,以及如何驗證圖表等更多細節内容。
2.4.1 圖表類型
做圖表有很多方法,不同的圖表在不同的情況下所發揮的作用不同。遇到的最多的圖表類型可能就是資料流圖(data flow diagram)。不過,你也能看到uml、泳道圖(swim lane diagram)、狀态圖。你可以把這些圖表看成樂高積木,仔細考慮哪個圖表最适合給目前軟體模組化。這裡的每一種圖表類型都可以與第二部分的威脅模型一起使用。
通過圖表,你可以了解到系統是如何運轉的,這樣參與威脅模組化的每一個人都有同樣的了解。如果你滿意對于軟體如何運轉的圖表,那麼在大家逐漸達成一緻的過程中,你很可能發現對系統的安全性了解錯誤。是以,使用圖表有助于溝通,形成共同的了解。
2.4.2 資料流圖
資料流模型經常是威脅模組化最理想的模型。安全問題經常是在資料流中出現,而不是在控制流中。資料流模型通常存在于網絡或者系統構架中,相比之下軟體産品較少,但也可以建立。
資料流圖的應用非常廣泛,有時會被稱為“威脅模組化圖”。1967年由larry constantine設計,資料流圖(dfd)包括帶編号的要素(資料存儲和過程),通過資料流連接配接起來,并與外部實體互相作用(在開發者或者組織控制之外的實體)。
資料流圖是以資料流命名,幾乎總是向兩個方向流動,也有例外,例如無線傳輸或udp協定傳輸到網際網路。盡管這樣,資料流經常用單向箭頭展現,因為威脅和它們的影響一般都是不可逆的。意思是說,如果到達web伺服器的資料流被讀取了,可能會暴露密碼或其他資料,反之,從web伺服器流出來的資料流可能會暴露你的銀行賬戶餘額。這一圖表規則并沒有闡明通道安全與消息安全的差别。(這個通道可能是smtp,而消息是電子郵件消息。)如果通道與消息的差別很重要,那麼采用泳道圖可能更為合适。(泳道圖會在本章後面講述。)
資料流圖的要素如表2-1所示。

圖2-3是基于表2-1中要素繪制的典型資料流圖。圖2-4顯示的是同一個模型,隻是做了一些變化,你可以用這個例子來改善自己的模型。
下面解釋從經典資料流圖到現代資料流圖的變化:
程序變成圓角矩形,與圓圈相比可以有更好的文本内容。
利用直線,而不是曲線,因為直線更容易使用,适合應用在大型圖表中。
過去,很多資料流圖的描述中既包含“程序”因素,又包含“複雜程序”因素。一個程序被描繪成一個圓圈,複雜程序則是兩個同心圓。但是什麼時候用一般程序,什麼時候用複雜程序,仍舊不夠清晰。區分二者的原則可以定義為:有子圖的就是複雜程序。“看起來有點圓”,聽上去也是個像樣的原則。
除了應用在軟體産品外,資料流圖還可以應用在多個案例上。例如,圖2-5用資料流圖展示了一個營運網絡案例,這是中小型公司網絡的典型模型,選取了典型系統和部門。附錄e中會深入讨論。
https://yqfile.alicdn.com/b44dbe76d5952c418f9343b5226f0c3ea5c12ec6.png
" >
統一模組化語言uml
uml為統一模組化語言的縮寫。如果你在軟體開發過程中使用uml,那麼你也可以用uml圖表進行威脅模組化,而不需要重新畫圖。利用uml繪制威脅模組化圖表最重要的是添加信任邊界。
uml相當複雜。舉例來說,visio的uml模闆用了80個左右符号,而用資料流圖的話隻需要6個。也正是由于這種複雜性,使人們畫結構圖、行為圖、互動圖時能展現出大量微妙之處,且表達能力更強。如果威脅模組化相關人員不熟悉所有uml符号,或者對于這些符号的意義了解有誤,圖表工具的有效性就會大打折扣。從理論上講,任何有困惑的人都可以提問,但是前提是他們知道自己有困惑(他們可能會假定代表魚的符号不包括鲨魚)。應該允許人們願意提一個“簡單”而暴露自己無知的問題。對于使用uml開展威脅模組化的團隊來說,給uml圖添加信任邊界要比重新建立新圖表更容易些。
泳道圖
泳道圖通常用于表達不同參與者之間的資料流。用長線繪制,每條線代表一個參與者,每個參與者都對應有一條線,每條道的邊上辨別每個參與者的身份。每條資訊都由參與者之間的一條線表示;時間是通過每條泳道向下的流向來表示。圖表有些像遊泳道,故而得名。每條資訊應以内容來辨別,如果内容太複雜,那麼就提取一些内容細節作為圖示的關鍵詞,使辨別更有意義。參與者計算的數值或狀态應該記錄在表示參與者的線旁。通常該協定中的參與者是如計算機這樣的實體,泳道圖通常在每個參與者之間有暗含的信任邊界。密碼學家、協定設計者carl ellison将泳道圖擴充至包括作為參與者的人,以此來研讨人們期待知道什麼、期待做什麼。他稱這種擴充為“儀式”,這将在第15章中更詳細地讨論。
圖2-6顯示一個泳道圖範例。
狀态圖
狀态圖顯示一個系統可能的不同狀态以及這些狀态間的轉換。一個計算機系統基于它所收到的有效資訊和存儲的資料,可被模組化成包含狀态、存儲、狀态轉換規則的機器(計算機測試收到的資訊,根據規則進行驗證)。每個方框标示一種狀态,之間的線标上标示狀态轉換條件。威脅模組化中你可以使用狀态圖,檢查每次狀态轉換是否經過恰當安全驗證。
https://yqfile.alicdn.com/fc225ec8be8034271eb887ecbe96a07ee5298663.png
圖2-7表示一個關于門的簡單的狀态機(源自維基百科)。一個門有三種狀态:開啟、關閉、鎖住,通過狀态轉換進入每個狀态。“門栓”系統比鎖上的旋鈕更好畫上去,因為後者從兩個狀态都能被鎖住,這就創造了複雜的圖表和使用者體驗。顯然,狀态圖很快就會變得複雜。你可以想象一個更為複雜的狀态圖,其中包括“半掩”,一個可以從關閉和開啟都能到達的狀态(我曾畫這個圖,但是填寫标簽時遇到了難處。顯然,門半掩着沒有明确指向,不該部署)。你并不隻是為了做架構決策而把模型設計得更簡單些,而是簡單的模型更易于使用,更易于反映出設計。
2.4.3 信任邊界
正如第1章中介紹的,信任邊界是不同主體彙聚的位置,也就是說,是實體與不同權限實體之間交叉的位置。
畫邊界
建立軟體模型之後,添加邊界的方法有兩種:添加你知道的邊界并尋找更多的邊界,或者列舉主體并尋找邊界。從邊界開始,盡量加入你所能加入的任何信任邊界。unix系統的uid、windows會話、機器、網段等之間的邊界要用方框來畫,每個方框裡面的主體都應添加标簽。
從主體入手,從特權範圍(通常是root/admin或者匿名網絡使用者)的一端或者另一端開始,然後每當其與“别人”對話了就添加邊界。
你總是能添加至少一個邊界,所有運算都會在某些情況下發生(是以,你可能會批評圖2-1中顯示的web用戶端和sql用戶端沒有辨別出背景)。
如果你不知道在哪裡畫一個信任邊界,你的圖表可能都在一個信任邊界裡,或者是你漏掉了邊界。問自己兩個問題:首先,系統裡所有要素是否都具有相同級别的權限,并且可以通路系統裡所有其他東西?其次,軟體裡的所有溝通交流都是在同一邊界内完成的嗎?隻要這兩個問題裡面有一個回答是否定的,那麼你就要馬上弄清楚,要麼遺漏了邊界,要麼圖中缺少了一個要素,要麼兩個問題都存在。如果兩個問題的回答都是肯定的,那麼你該在所有實體之外畫一個信任邊界,然後繼續其他開發活動。(這種狀态是不太可能的,除非是開發團隊每一部分都建立了一個軟體模型。“自下而上”的方法将在第7章中詳細讨論。)
很多威脅模組化的著作都宣稱信任邊界應該隻涉及資料流,這對威脅模組化中最詳細級别的設計來說很有用。如果信任邊界涉及資料存儲(即資料庫),這可能表示有不同信任級别的資料表或者存儲過程;如果信任邊界涉及一個既定主機,這可能表示比如每一個“軟體安裝程式”在“網絡内容更新”時有不同的權限;如果你發現信任邊界涉及資料流之外的其他要素,要麼将該要素一分為二(在模型中,或在現實中,或者是兩者),要麼畫子程式圖來表示它們被分成多個實體。好的威脅模型最關鍵是劃清楚邊界在哪,以及如何保護邊界。反之,沒有清晰的邊界劃分和認識,就不能建立好的模型。
使用信任邊界
威脅常常與信任邊界是密切相關的。這一點是顯然的:信任邊界勾勒出各個主體之間的攻擊界面。一些人認為威脅隻出現在邊界主體之間,或者出現在信任邊界上。這種假設有時是不準确的。原因是,假設一台web伺服器需要進行一系列複雜的訂購過程。例如,戴爾網上商店要組裝一台電腦,會加入幾千個零件,但是隻有一部分是經過檢測,可以出售的。我們可以構造出圖2-8所示的網站模型。
如圖2-8所示,盡管web伺服器是通過可信的tcp/ip堆棧進行會話,顯然它也有可能受到來自網絡浏覽器的攻擊風險。同樣,銷售子產品也存在風險;雖然訂單處理子產品中對html送出的資料進行校驗,但攻擊者仍能夠在送出html中插入随機的零件編碼。即使在銷售子產品和訂購子產品沒有信任邊界,即使資料在三個邊界都進行校驗,威脅仍然跟随着資料在流動。由于客戶僅作為一個外部實體,是以在圖中被表示為網絡浏覽器。當然,web浏覽器還有許多其他元件,但是如果沒有對它們做任何威脅分析,那為什麼給它們做模型呢?
是以,更确切地說,威脅往往會在信任邊界和複雜解析過程中彙聚,但是也可能出現在攻擊者能夠控制資訊的任何地方。
2.4.4 圖表中包含的内容
那麼圖表中應該包括哪些内容呢?以下是一些經驗法則:
顯示推動系統的事件
顯示驅動的程序
判定每個程序将産生和發送什麼響應
識别每個請求和響應的資料來源
識别每個響應的接收者
忽略内在運作機制,重點關注範圍
回答是否有什麼能輔助你思考哪裡出錯了,或者有什麼可以幫助你找到威脅
這個清單來自howard和leblanc的《編寫安全代碼(第2版)》(writing secure code,second edition)(microsoft press,2009)。
2.4.5 複雜圖
當你建構一個複雜系統時,圖會很複雜。系統變得複雜,繪制圖表(或者了解整個系統)就變得很困難。
一條原則是“不要畫成視力檢查表”。一個真實的軟體開發項目包含很多細節,而在模型中也需要包含這些細節,做好二者之間的平衡是很重要的。正如第1章提到的,為了實作平衡,可以利用子圖來顯示一個特定區域的細節。你需要采用很多合适的方法來拆解和描述你的項目中各個詳細的技術領域。例如,假設有一個非常複雜的過程,可能這一過程本身構成一個圖,過程以外的東西構成另外的圖。假設有一個排程員或者排隊系統,這可能是進行拆解的好地方。或許你的資料庫或者故障轉移系統是拆解的好地方。或許有一些要素确實需要更多細節,這些都是可以拆解的好方法。
做子圖時要注意,子圖的數量不要多于上一級主圖的數量;另一種方法是利用不同的圖來表現不同的場景。
有時,簡化圖表也是有用的。當圖中的兩個要素從安全角度來看是等效的,那麼你可以讓這二者合并成一個。等效是指在同一個信任邊界内部,且依賴于同一技術,處理相同資料的一組要素。
切記,圖表是用來幫助我們了解系統和展開讨論的。正如本書開始時說的“一切模型都是錯誤的,隻有一些是有用的”。是以,在你添加額外的圖時,不要想:“這麼做是正确的嗎?”而是問:“這對我們思考哪裡出錯有幫助嗎?”
2.4.6 圖的标簽
圖的标簽要簡潔明了。因為你想要用這些标簽的名字去講故事,是以首先從驅動系統的外部實體開始。那些都是名詞,如“客戶”或“振動傳感器”。它們通過資料流傳輸資訊,這些用名詞或者名詞短語标注,例如“要買的書”或“振動頻率”。資料流從來不用動詞來标注。雖然會比較難,但是你應盡量找些有意義的詞作為标簽,并用箭頭方向來表示“讀”或“寫”。換句話說,資料流将資訊(名詞)傳遞到過程,過程是動态的:動詞、動詞短語或者動名詞短語。
很多人發現用序号标注資料流非常有用,可幫助追蹤事件發生的順序。将圖中的要素标注數字可以幫助保持圖的完整性或易于交流。你可以給每個東西分别标注數字(資料流1、過程1等等)或者你可以在圖表裡統一标注數字,例如外部實體1與過程4對話,是通過資料流2和資料流3。通常,所有事物統一标注數字會比較清晰。你可以說“1号”而非“資料流1号,不是過程1号”。
2.4.7 圖中的顔色
顔色可以添加大量資訊,例如,微軟的peter torr使用綠色表示可信任的,紅色為不可信任的,藍色表示正被模組化的(torr,2005)。然而完全依賴于顔色是有問題的,因為約有1/12的人是色盲,他們大部分還是紅綠色盲(heitgerd,2008)。即使有彩色列印機,還有一部分人不能完全獲得顔色想要表達的資訊。用帶有标簽的邊框可以解決這個問題。有了帶邊框的信任邊界,就沒有理由使用顔色了。
2.4.8 入口點
威脅模組化的一種早期方法是“資産/入口點”法,在對作業系統進行模組化時非常有效。該方法可以分解成以下幾個步驟:
1.繪制資料流圖。
2.找到資料流中跨越信任邊界的點。
3.将資料流和信任邊界的交叉點标為“入口點”。
還有很多其他步驟和方法,但是我們作為一個團體已經學習了很多,重新完整解釋會令人乏味和注意力分散。
在acme/sql示例中(如圖2-1所示),入口點是“前端”和“資料庫管理”控制過程。“資料庫”也是一個入口點,因為名義上,其他軟體可以在資料庫改變資料,可以使用資料解析故障來獲得對系統的控制。對于财務來說,入口點是“對外輸出報表”、“财務規劃和分析”、“核心财務軟體”、“銷售”和“應收賬款”。
2.4.9 表驗證
驗證得到的表是否是軟體最恰當的模型的目的有兩個:保證準确性和結果完美。第一個目标較為容易,因為你可以對該圖是否反映了實際狀況征求意見。如果圖表缺失了重要部件,或者圖顯示的東西并不存在,那麼可以知道沒有反映事實。如果圖中缺少重要的資料流,或出現了并不存在的資料流,那也沒有反映事實。如果不編輯圖你無法講出軟體的故事,那麼也是不準确的。
當然,“重要性”也引出第二個标準:結果完美。重要的是能幫你找到問題,尋找問題時可以問自己這樣的問題:“這個要素有沒有安全影響”,“是不是有時發生或者在特定情況下才發生”。獲得問題答案是個經驗問題,就像建構軟體的多個方面。一個好的、經驗豐富的架構師能快速評估需求并解決它們,一個好的威脅模組化者可以很快了解哪些要素是最重要的。達到這種經驗水準很大程度上要靠多練習。本書第二部分涉及的系統的尋找威脅方法,旨在幫助你識别哪些要素是重要的。
如何驗證圖
為了更好地驗證圖,讓最了解這個系統的人員聚在一起,要有人站在圖前,排查重要的用例,確定以下幾點:
他們能充分讨論圖要描述的故事。
在目前情況下,他們無須改動圖表。
他們無須提到圖中沒有出現的事物。
當你更新圖表、積累經驗時,這些經驗法則會很有用:
任何時候聽到有人說“有時”或“也”時,都應考慮加入更多細節來拆解諸多場景。例如,如果你說:“有時我們通過ssl連接配接到web伺服器,有時需要回歸使用http。”這兩種資料流你都要畫上(并思考攻擊者是否會讓你那樣回退)。
每當你需要更多細節來解釋安全相關行為時,都需要畫到圖上。
每個信任邊界邊框都必須有一個标簽。
每當你對系統設計或者建構有不同意見時,将那些細節畫到圖上。為了讓所有人保持進度一緻,這是很重要的一步,對于不是所有人都能聚在一起對威脅模組化進行讨論的大型團隊尤為重要。任何人看到得到的圖與他們的想法相沖突的時候,他們都可以要麼接受它,要麼挑戰這個假設,不管是哪一個,清晰準确的圖表可以讓每個人保持相同進度。
不要有資料池:你寫的資料是要有原因的,要表示出誰在使用這些資料。
資料不能從一個存儲區轉移到另一個存儲區,要表示出其移動的過程。
所有資料到達的方式都應表示出來。
如果有控制資料流的機制(例如防火牆、通路權限)也要表示出來。
所有過程必須至少有一個入口資料流和一個出口資料流。
如前面講過,不要畫成視力檢查表。
圖表要能列印出來。
《撰寫安全代碼》(writing secure code)的作者david leblanc表示:“一個過程沒有輸入時是個奇迹,而沒有輸出就是黑洞。要麼你遺漏了東西,要麼已經把過程誤以為是被允許成為黑洞或是奇迹的人。”
什麼時候驗證圖表
對于軟體産品,有兩個主要的驗證圖表時間:建立的時候和準備釋出測試版的時候。還有第三個觸發事件(不那麼常見),就是你添加安全邊界時。
對于可操作的軟體圖表,在圖表建立的時候進行驗證,然後在效果與最新的輸出之間做權衡來确定是否需要再次驗證。這種權衡會根據系統的成熟度、規模、元件間的緊密程度、首次展示的節奏、新産品本質等有所不同。在此提供一些指南:
相比成熟的系統,新系統會經曆更多次的圖表改變。
相比小型系統,大型系統會經曆更多次的圖表改變。
相比松耦合系統,緊耦合系統會經曆更多次的圖表改變。
系統上線便盡快做出修改将在以後每次展示時經曆較少次的圖表改變。
關注重構或技術的上線或沖刺可能會經曆更多的圖表改變。不論哪種情況,建立一個合适的追蹤項目,確定在合适的時間對你的圖表進行重新檢查。适當的追蹤項目是盡量地延遲軟體的釋出或上線,例如缺陷、任務管理軟體或檢查清單。如果沒有辦法延遲軟體釋出的方法,那麼在擔心是否需要檢查威脅模組化之前,你可能要關注是否有明确規定的釋出過程。該過程描述不在本書讨論範圍内。