特色與功能(而非安全)向來是多數公司在進行軟體開發時,最先想到的部分。然而,因為疏忽安全而造成的代價卻可能很高:暴露機密資料、客戶帳號被竊,以及產生難以數計的漏洞。
這些問題大多可以藉由一開始的軟體開發階段安全規劃加以避免。架構、設計與程式的撰寫提供了許多機會,可以讓我們加強軟體或服務的安全性。透過在整個開發週期對於安全進行通盤的考量─定義安全需求、將資料分級、撰寫防駭程式碼,以及實施周密的測試─你便能夠從一開始就擁有安全的應用軟體。
各就各位,準備,開始!
需求與規格書
軟體開發生命週期(SDLC, Software Development Life Cycle)是軟體開發專案的長程規劃,它有許多種類型,包括:瀑布式(Waterfall)、反覆式(Iterative)、雛形式(Prototyping)與螺旋式(Spiral)等。每種類型都有其優缺點與特定的階段規劃,不過有些步驟卻是共同的:那就是定義軟體需求(包括安全在內),讓大家都瞭解需要建構哪些功能。
軟體需求規格書(Software Requirement Specification,SRS)的用途是將軟體的效能需求與安全功能,傳達給整個團隊知道。規格書的形式不拘,內容可能很簡潔(例如只有臨機操作〔ad-hoc〕指令),也可以像是正式文件非常詳盡。無論是從編制上或者地理上來看,你距離開發人員越遙遠,就應該讓規格書越詳細明瞭。舉例而言,清楚地說明每種介面(網頁、命令列指令、API)的認證等級,將可以避免程式開發人員對於應用程式環境所需的信任等級,做出自己的假設。對於外包的專案而言,將專案的功能與安全需求做出清楚的陳述,是絕對必要的工作。
資料分級
在定義完軟體需求之後,下一個步驟便是對資料進行分級。儘管通常不會一開始就以獨立的軟體開發生命週期來進行規劃,不過當我們所關注的焦點是安全方面的努力時,資料分級便顯得非常重要了,而且可以幫助我們在專案初期就避免犯許多代價不菲的錯誤。藉由檢視將被應用程式取得或處理的資料,然後根據資料的內容分類為組織內部的、敏感機密的與合法的等需求,將可以讓你在提供資料之前,先對安全嚴格把關。舉例而言,公司可能並不介意是誰下載了產品型錄,但是可能就不希望看到優惠價目表也被印出來了。一般而言,在進行資料的分級時,最好還是採取簡單的方法。隨著類別數量的增加,分級管理也會更加困難:在每套軟體發佈時,你都必須不斷地檢查資訊是否歸屬於正確的類別。
舉例而言,HIPAA(美國醫療保險行動性和責任性法案,Health Insurance Portability and Accountability Act)將個人醫療照護資訊定義為必須保護的資料,因此包含個人與非個人醫療照護資訊的類別就必須被嚴格地區分開來,以符合規定。
換個情況來看,組織可能會選擇使用四種類別:標示為「高級」的資訊,一旦被洩漏了,將可能導致信譽掃地,故應該予以加設密碼保護;「中級」可以用來標示優惠價目表;「低級」包含的是標準的價目表與白皮書;而「公開」則可能是市場推廣資料與網站本身。
架構與設計
程式的架構與設計可能影響應用程式的安全性,如同大樓的建築風格會影響整體安全是一樣的:例如附近範圍內的活動窗戶就是很實際的安全威脅,就像程式漏洞會大開攻擊之門。
任何應用程式架構的決策,都必須考慮到應用程式所要處理的資料類型,以及這些資料的完整性與安全性是否會因結構上的選擇而可能遭受威脅。舉例而言,選擇將客戶資訊儲存在只對公開資訊有設保護的資料庫上,就是個很不好的決策。相反地,決定使用有口碑的第三方身分管理服務,而非在應用程式內建構新的認證儲存機制,將可以提高應用程式的安全性,因為這樣的系統並不是那麼容易開發。
同樣地,軟體產品的設計也應該將重點放在最有可能會影響安全的那些元件上,比方說輸入的驗證、認證、授權、錯誤處理,以及狀態記錄。假使有使用第三方或商用或開放原始碼軟體來作為元件的話,那麼使用到的部分必須和應用程式的程式碼一樣安全,以確保這些東西所提供的服務無損於應用程式的安全。
與你的團隊針對軟體需求進行有效的溝通是非常重要的,因為這樣可以確保每個人處理的是位於文件同一頁上面的事情,以及安全目標是否完全達成。在避免犯錯這方面,有效溝通與團隊合作是非常有幫助的,因為這兩點可以確保開發人員與測試人員不會有根據錯誤假設而做出錯誤決策的情形發生─這樣程式碼也就比較不容易遭致攻擊。
撰寫防駭程式
對安全來說,程式的開發與撰寫是非常關鍵的階段(需求、架構和設計都在此期間完成)。開發人員需要瞭解應用程式有哪些安全威脅,也必須知道常見的程式撰寫錯誤,比方說緩衝區溢位、隱碼弱點(injection flaw),以及可能導致產生安全漏洞的無效輸入。在開發過程中,安全方面的經驗是無法替代的。需由所有人員(包括架構規劃師、設計者、測試人員,以及管理階層)共同努力,而非全是開發人員的責任。
假使團隊並無相關的安全經驗,那麼就動手發展與培養這方面的知識吧。讓開發人員閱讀像是《Writing Secure Code》(作者是Howard和LeBlanc)和《The Open Web Application Security Project (OWASP) Guide to Building Secure Web Applications》這類的書籍,或者是讓他們去報考開發導向安全認證,譬如Microsoft的MCSE: Security和Sun Microsystem的SCD/WS。
運用在職訓練也是不錯的方法。當某個應用程式發生安全事件(security incident)的時候,帶著開發人員去參與事件應變處理。在這些事故都被解決之後,舉行公開的事後檢討會議,以便與全體員工分享處理事件的細節與經驗。讓員工有機會參與內部與外部的程式碼安全性檢閱工作。此外,還有一點也非常重要,就是瞭解哪些程式語言特別容易發生哪種錯誤。C容易發生的錯誤包括:緩衝區溢位、未正確結尾的字串,以及記憶體漏洞(memory leak)。PERL的問題是安裝與有效範圍的界定容易不明確。而PHP則容易造成不安全的設定;許多第三方可重複使用的PHP元件都潛藏著瑕疵漏洞,這使得PHP成為美國國家漏洞資料庫中,最常被引用到的程式語言之一。
Java同樣容易有緩衝區溢位的問題,不過衍生的後果就沒那麼嚴重了。如果C開發人員犯了一個緩衝區溢位的錯誤,那麼攻擊者可能利用這個瑕疵在應用程式內插入程式碼。然而如果是Java開發人員犯了相似的錯誤,攻擊者也許可以讓應用程式當機,但是卻無法隨意插入程式碼。
根據所使用的程式語言,有一些不同的工具可以用來協助開發防駭程式。針對C,Safe Strings工具程式庫可以幫助隔絕緩衝區溢位錯誤。而標籤程式庫(tag library)─例如Struts的JSP標籤程式庫─以及搭配原始碼分析器(例如FindBugs)的Eclipse整合開發工具,則適用於Java。
另一方面,應用程式本身也可以開發成具備自我測試(self-testing)與自我糾正(self-correcting)的能力。舉例而言,像Apache網頁伺服器軟體就不會採用無法完全受檔案系統保護的安全憑證。
程式檢閱
最簡單的也是最容易被遺忘的程式撰寫錯誤,可以在檢閱程式碼時被抓出來。程式的安全性檢閱,必須檢查各式各樣的安全問題,從簡單的到正規的都有。你可以設立「程式搭檔」(code buddy)系統,讓開發人員互相檢視彼此的程式碼;或者是「程式檢視」(code reading)系統,讓開發人員可以將自己的程式碼呈現給開發團隊裡面的更多人看到─這會讓程式的原創開發人員考慮到應該清楚闡述設計的原理,以及驗證每個程式碼區塊的正確性。此外,藉由導入內部與外部(透過採用其他共同專案、別的部門或者第三方的檢閱人員)的程式檢閱制度,你將有更高層次的機會,可以站在第一線捕捉錯誤。
無論你選擇的檢閱方式為何,有幾項步驟是你一定得遵守的,以便確保程式碼的安全性:
-
指派一位秘書,將討論過程的意見與需要改進之處記錄下來。
-
複習以往在類似的程式碼中曾經看過的常見錯誤。
-
請程式搭檔或開發人員簡報程式流程。
-
針對每個基本功能區塊、函式或方法,去思考是否存在常見的錯誤,例如:所有輸入都是有效的嗎?所有錯誤狀況都有被處理到嗎?適當的地方有適當的存取控制嗎?緩衝區(在C裡面還包括字串)已做好溢位的防護了嗎?敏感資料的儲存是否安全?包含機密資訊(例如密碼)的暫存變數在使用後是否清除了?
-
將所有漏洞與問題,輸入到錯誤資料庫(bug database)當中。
-
更新常見錯誤清單,以供下次程式檢閱時參考。
整合與測試
安全測試(包含功能、可靠性與效能測試)可以告訴你距離準備好可以將應用程式正式上線還差多遠。在初期便展開安全測試,並且盡可能地與開發同時進行,將可以讓你提早獲知結果,這有點類似於選舉投票日的出口民調。此外,用一般標準來評估弱點與測試的結果,然後將你所學到的東西回饋到開發與程式檢閱的流程當中。
滲透測試(Penetration Testing)及應用程式弱點測試是整合與測試階段的重要工作。如同你為了讓應用程式上線所做的準備,掃描網路與系統將被用來檢測所有的程式碼,以確認網路與系統都沒有因為執行應用程式而停止運作。在你認為已經完成測試之前,還要先確定沒有開啟未使用的通訊埠或者啟用多餘的服務。此外,請測試人員試著透過傳入錯誤資料,或者藉由製造惡意資料來中斷應用程式,然後在首次公開展示之前,將所有發現的弱點修正完畢。再將應用程式的程式碼移往真正的運作環境之前,實施通訊埠掃描,並且重複滲透測試,以便在正式上線之前,先確定環境的設定正確無誤。
上線與維護
在維護階段,不良的程式體質會被放大檢視,如此也就容易滋生漏洞。管理階層往往是將新進開發人員放到維護階段,這可能會造成一些問題。如果你選擇這麼做的話,最好確定有更具經驗的開發人員可以指導這些菜鳥,並且檢閱他們的程式碼。
程式撰寫標準─包括命名、語言結構的用法,以及註解規範─有助於防止誤解的產生與弱點的導入。有可能因為原始碼裡面的註解不足,而導致開發人員試著加入的功能,或者試著修正的錯誤,邁向全然錯誤的方向。
此外,應用程式的開發人員可以藉由往前多想幾步,來協助避免維護性問題的發生,例如試想,從現在起的兩年內,有人可以瞭解程式決策背後的論據嗎?變數與函式名稱是否有意義?在程式比較有技巧性的部分,是否有任何解說的註解,或者這麼說,是否所有的程式碼都有註解呢?有個不錯的策略是,要求開發人員在一段時間之內,必須對他們自己維護的部分負責。如果程式是他們寫的,那麼在接下來的兩年內,他們就必須負責修正其中發現的漏洞;要是他們寫的程式不夠安全的話,風險就是可能會在半夜兩點因為發生安全事故而接到電話。許多時候,對於程式設計師來說,能夠讓他們的耳根清淨是相當有效的激勵方式,可以促使他們撰寫安全的程式碼。
為了確保應用程式在維護期間,以及整個軟體開發生命週期的安全性,所要採取的步驟需要相當多的時間與努力。不過這種初期投資是非常值得的。一旦軟體被開發完成,要回過頭來加強安全,是比較困難而且花費更昂貴的。到了那個時候,你可能會發現自己正站在裂縫的中間,感覺像是公司被放在熱水裡面一樣。如果從很早便開始規劃安全,那麼未來必須煩惱的安全問題將會少之又少。
Michael Jordan(擁有CISM資格認證)是SystemExperts公司顧問。