在
軟件開發初期處理安全需求是防止安全問題最經濟的方式。大多數安全需求都屬于非功能性需求(Non-Functional Requirements ,NFRs)。很多從業者發現,在
敏捷項目中處理安全和其他NFR非常具有挑戰性。原因有二:
匹配NFR和特性驅動的用戶故事需要付出很大努力;
安全控制常因缺少可見度而被忽視。敏捷過程容易讓團隊不自覺地側重于那些可以直觀改善客戶體驗 的新功能開發或缺陷修復。
在本文中,我們會探討以上兩個問題。
在用戶故事中處理NFR
敏捷專家們提出過一些方法,用以定義用戶故事驅動的開發過程中的NFR。Mike Cohn在他的
文章中討論了評論者們提出的一些有趣的建議。Scott Ambler就該主題寫了一系列文章,旨在證明并非所有的NFR都可以獨立存在于用戶故事中。而Dean Leffingwell可以說在這方面做了最深入的研究,他在自己的著作《敏捷軟件需求》中花了整整一章探討該主題。這些專家中大部分人都認為,NFR大致可以分成兩類:
非功能性用戶故事:以用戶故事的形式展現的可
測試功能塊。這些用戶故事中的參與者(Actor)可能是內部IT人員。例如:“作為安全分析師,我希望系統能抑制不成功的身份認證嘗試,這樣應用程序在面對暴力破解時不至于太過脆弱”。
約束:這是個跨領域的問題,常常涉及多個用戶故事。我們可以將它看作是對所有相關開發
工作收取“課稅”。例如:開發Web應用時,要求所有開發者對Http表單中的字段進行數據校驗即為一種約束。
處理第一類NFR很簡單:創建一系列的NFR用戶故事,將它們加入某種工作序列,例如Product Backlog。
NFR約束的挑戰:
然而處理第二類NFR則困難很多。敏捷專家們對此提出過一些解決辦法,包括:
在特定的用戶故事中添加恰當的約束作為驗收標準
在某個中央知識庫——例如,貼在墻上或者發表在wiki上的一份文件——中維護包含所有約束的列表。
但無論哪個方法都無法解決的問題是,如何針對特定的用戶故事選擇適用的約束。而且,使用SD Elements進行安全需求匹配的經驗表明,要將這些技術限定在一定范圍之內很困難。下面這個列表是標準Web應用需要面對的安全約束中的一部分,我們以此為例:
對來自客戶端的只讀數據進行完整性驗證,以防止參數篡改
避開存在于HTML、HTML屬性、CSS以及JavaScript中的不可信數據,從而防止跨站點腳本攻擊)(XSS)
避免客戶端JavaScript中基于DOM的XSS
使用安全的算法以避免整型溢出
不接受外部重定向以防止自由重定向攻擊
授權給受保護的頁面,以防止權限提升攻擊)
使用防止跨站請求偽造(CSRF)的令牌
驗證輸入
盡量使用正則表達式,因為它對于拒絕服務攻擊有較強的抵抗力。
為高價值的事務實現事務身份認證
不要硬編碼密碼
該列表列舉的可能只是程序員在實現用戶故事時需要考慮的安全約束中的一小部分。若將需要遵循的法規標準——諸如支付卡行業數據安全標準(PCI DSS)之類——考慮在內,約束還要增加不少。如果你開始添加其他NFR約束,例如可訪問性,約束列表會快速增長,轉眼間就會超過程序員的承受范圍。一旦列表變得臃腫,我們的經驗是,程序員往往會將它全部忽略,僅根據自己的記憶來應用NFR約束。而在很多不斷專業化的領域——例如應用安全——NFR的數量不斷增長,這給程序員的記憶力造成了沉重的認知負擔。因此,如何使用靜態分析技術偵測代碼中違背NFR約束之處就成了關注重點。研究表明,靜態分析可以偵測出的可預防缺陷最多不超過總數的40%,也就是說仍有大量的約束漏網,包括特定領域的安全控制,更別說在缺乏定制的情況下辨別靜態分析產生的“假陽性”結果也不是那么簡單。
應對NFR約束的挑戰
為了解決NFR約束過多的問題,我們需要做到以下四點:
按優先級排序:與用戶故事和缺陷一樣,NFR約束也應擁有不同的優先級,例如:相較于避開HTML中的不可信數據以防止持續的跨站腳本攻擊,對HTTP響應頭中的不可信數據進行編碼或校驗以防止HTTP響應拆分攻擊就不那么重要。因此我們假定程序員通常沒有足夠的時間處理所有約束,然后我們提供一種機制為如何定義約束的相對優先級提供建議。之所以說“建議”,是因為優先級有可能隨著具體情況的變化而變化,程序員需要自己作出判斷——對于他們的特定代碼,哪種相對優先級是適用的。你可以選用簡單的優先級設置,如“高、中、低”,也可以使用數字范圍,如1-10。
過濾:使用簡單的標準常常就可以為特定的用戶故事移除大量的NFR約束。舉例來說,假如你正在實現的用戶故事與表現層無關,那么就可以安全地忽略大量表現層相關的約束。使用標簽系統或者簡單的Excel過濾器,就可以為特定的用戶故事削減約束數量。以下是一些Web應用相關的安全性約束過濾器的范例:
用戶故事是否涉及用戶輸入;
用戶故事是否涉及保密數據,如密碼、信用卡信息以及非公開的財務數據;
用戶故事是否返回一個全新或修正過的用戶輸出,例如一個網頁;
用戶故事是否會暴露或使用來自RESTful 或SOAP API調用的數據;
用戶故事是否會訪問受保護的數據(例如,不是所有用戶都能查看或修改的數據)。
情境(Context):程序員在寫代碼或定義任務單(tickets)/ 用戶故事的時候更容易記起并應用約束。理想情況下,如果把約束列表內嵌入IDE或任務單系統,那么程序員就可以在編碼時獲取相關的約束。既然現在很多IDE都支持內嵌的Web瀏覽器,那么使用輕量級的網站或者SharePoint站點就可以實現這個目標。
框架:框架可以大幅減少約束產生的“稅收”。例如,像 Django這樣的框架自帶了CSRF防護,這意味著程序員可以安全地忽略該約束,除非他們主動繞過這個內建的功能。根據我們的經驗,多數大型的應用軟件都會采用某種形式的定制框架,這些框架可以無縫處理最高優先級的約束。雖然這樣的框架定制可能需要較高的先期投入,但如果你將約束看成一種基于用戶故事的“稅收”,那么減少約束數量就相當于永久性的降低了“稅率”。
驗證
雖然主動處理NFR很重要,但仍有必要進行驗證。如果你有手動代碼審查(Code Review)的經驗,就可以檢查用戶故事中作為驗收標準出現的NFR。然而,如果僅使用手動代碼審查,很多約束的驗證將是非常棘手或者繁重的。靜態分析工具則可以自動檢查編碼標準的遵守情況,其中一些產品特別關注安全方面。將你的靜態分析工具與持續集成過程整合在一起,可以幫助你始終遵守編碼標準。但也務必注意,不要一味依賴于代碼審查。防范特定領域缺陷——如HTTP參數篡改——的NFR要求對背后的業務領域有深刻的理解。將手動驗證與針對特定攻擊的自動測試結合起來,可以幫助我們建立一套對于特定領域缺陷擁有更強抵抗力的系統。
可見度
難以將安全需求集成進敏捷項目的另一方面原因是安全需求通常缺乏可見度。面向客戶的會議,如Scrum的Sprint評審會議),容易使開發人員產生一種固有的傾向,即實現用戶故事或修復缺陷時傾向于那些能直接改善用戶體驗的故事或缺陷。一部分非功能屬性,例如易用性和性能,對于系統的使用體驗有具體的影響,因此也比較容易向客戶展示。而另外一些——如安全性——卻很難在Sprint評審會議上給客戶留下很好的印象。實際上,某些安全特性,如賬號封鎖(Account Lockout),可能給客戶體驗帶來相當負面的影響。大多數安全特性對系統的影響,普通用戶很難察覺。因此,安全性NFR是不可見的,它們必須和可見度更好的特性競爭,以奪得寶貴的開發周期。在軟件開發初期,準確的說在程序員應該構建安全特性的時候,處理這些“隱形”需求的機會成本會特別高。
讓安全特性可見
對于敏捷團隊來說,沒有“銀彈”能讓安全需求在開發伊始就擁有最高優先級。但有一些方法可以讓安全NFR對客戶和/或PO可見。
圖形化安全用戶故事:如果你在應用程序安全方面足夠專業,就可以針對已知的安全弱點創建一套全面的安全控制。然后將它們與NFR用戶故事匹配起來,并繪制簡單的圖形,用以說明系統中已實現的和未實現的安全用戶故事數量。這個圖可以放在大型可視圖表中。
圖1:安全用戶故事圖
當然,這個圖沒必要局限于安全用戶故事,你可以將其他重要的NFR囊括進來。實際上,你可以使用故事點(Story Point)取代用戶故事數量,從而更準確的反映工作量。另外,你有可能希望圖中只記錄那些針對高風險安全問題的、擁有最高優先級的用戶故事或控制。每完成一個故事,“已完成”數量都會增加,客戶也會籍由此圖直觀地了解項目的進度。
展示可利用性(exploitability):沒有什么比可利用性展示更能讓人們理解一個安全漏洞的各個方面了。這是安全性滲透測試和漏洞評估的主要區別。你可以展示在上一版本的應用中如何成功地利用了漏洞,而在新的版本中卻沒辦法這么做了。然后你可以從對業務和/或客戶影響的角度解釋漏洞的方方面面。這非常有利于解釋為什么在安全控制上花的時間是合理的。
結論
主動處理NFR,特別是安全特性,在敏捷環境中非常重要。不少專家對于如何處理此類需求——特別是當它們與創建用戶故事相關時——給出了建議。全面地處理約束是個相當大的挑戰。記住本文討論的提議,你可以極大地增加維護一系列約束的價值。即使不能完全做到以上所提的四點內容以改善對約束的管理,但從長遠來看,任何一點改進都能帶來很高的回報。進行驗證能保證團隊始終遵守NFR。最后,提高安全特性的可見度,可以讓你證明用在NFR上的時間是合理的,就算它們對系統的改善不能反映到用戶體驗上。