該如何寫出更好的軟體?─ 系列訪談之二 (中)

此為 Mozilla Hacks  部落格的新系列訪談之二。如果你才剛看到這篇文章,當然不要錯過《該如何寫出更好的軟體?─ 系列訪談之二 (上)》篇。

在 API 或通訊協定工程師坐在位子上寫程式之前,應該先考慮哪些事情?

我認為該先考慮使用者到底需要什麼,歸納出使用者的期待而完成最基本、最低限度的東西。再試著寫出能滿足這些需求的最輕量程式碼,並搭配最小程度的資源。

這聽起來像是要開發「投機取巧」版的通訊協定?

是的,「限制程式進行最單純的作業」很有效。只要基礎 API 可達到所需的目標,你就應該接著思考同樣 API 可能造成的反效果。試著去避免這些反效果,否則可能最後得不償失。

安全的一大問題,就是你有時候會問「X 發生的機率有多大」。如果你設計的東西有 1/1000 機率會發生某件事情,也就等於某一連串的特定輸入能造成特定問題。如果真的是隨機的,那麼 1/1000 也還好;1/1000000 也還好。不過只要駭客完全掌握這特定的輸入時,任何錯誤機率都變得毫無意義,遲早會變成 100% 出問題。

其實這是一種智力上的比拼。做一堆案例分析就想歸納出所有可能發生的事件、可能產生的情況,可說是徒勞無功。只要想挖出漏洞,就必須進行這些分析作業。又,如果對方分析得更全面,就能進一步找到你遺漏的問題。

這就是所謂的威脅模型分析 (Threat modelling) 嗎?

是的。不同人對這個詞也有不同的說明方式。在你配置系統時,也就跟著在設定基本規則。如果以遊戲為例,就是讓小明選擇一組密碼,再讓小華試著猜出這組密碼。

這就是在定義基本規則。有時候會直接挑明了像是「駭客不能在防禦性系統上執行作業」這類的規則,而只能透過此單一的 API 呼叫進行存取,這同時也等於你提供給正常玩家的 API 呼叫。當然,你無法分辨誰是好玩家或是駭客。且這兩種玩家也都使用相同的 API。

講到這裡你就了解:駭客能對安全屬性動的手腳就是製造 API 呼叫。他們可以努力猜密碼,或是給你一些你意料之外的輸入值,設法造成緩衝區溢位 (Buffer overflow)。

但你會思考我到底在說怎樣的假設情況,真的成立嗎?你先按照之前講過的假設情況 (即:本來可阻止駭客看到資料庫,但只要系統某個部分出錯,就會讓其他人看得一清二楚) 來把密碼儲存於資料庫。再修改一下假設:大多數的駭客都看不到這個資料庫,但有時候卻可以。這樣一來,你該如何保護資料庫中的東西呢?

你另外要考慮需阻止哪些不同的威脅。你有時候在沙地上畫一條線並宣佈「我們要阻擋這個水準之內的所有攻擊,但如果超過這個水準就束手無策了」。這種限制往往還蠻現實的,像是牽涉到「我們會抵禦這類攻擊,但必須多花五倍的成本」。

廠商會估算駭客與使用者之間的成本,有點像是用期望值算出來的保險分析,再考慮是否要動用更高的安全機制。假設駭客必須花上「X」的成本,也要根據被逮到的風險算出期望利益「Y」。

系統有時候可重新配置,進而鼓勵他們做好事。像是比特幣 (Bitcoin) 當初就經過很縝密的思考,但再怎麼單純的東西也一定會引來壞人的覬覦。總有人想加快速度,或進行與系統背道而馳的事情。所有人都知道,如果包含駭客在內的所有人都將心力用在正途上,就能讓大家享受更好的東西,而且也能獲得更高收益。所以好的駭客也能成為絕佳的參與者。

圖片來源:http://www.forbes.com/sites/robertwood/2013/05/05/sorry-bitcoin-irs-gets-reports/

數位資安當然重要,前陣子沸沸揚揚的比特幣亦然。圖片來源:http://www.forbes.com/

系統設計師該如何儘量開發合理的安全系統?

我推薦《Principle of Least Authority》當做指南。POLA 有時如同其名,任何元件僅具備其進行特定作業所需的最低限度功能。這也代表了一連串的定義,其中之一就是「應該以不同元件配置自己的系統」,而且這些元件應該各自獨立。即使其中之一損壞或運作錯誤,至少能將傷害控制在最低限度。

我最愛拿解壓縮方式當範例。像是「gzip」會在你進行其他程序之前,先試著展開檔案。把這款軟體想成獨立的元件,一端應該接著壓縮的位元組;另一端則是輸出解壓縮的資料。此作業將配置記憶體並執行各種格式處理、查詢表格等作業。不論輸入何種奇怪的資料,或是其處理方式發生什麼樣的問題或錯誤,也都只會限於單純的輸出作業。

這有點像 Unix 管理程序的方法。但差別在於 Unix 程序所執行的 syscalls 可能毀了你整個磁碟,也可能拖慢網路速度或造成其他負面影響。但我剛舉的例子僅止於「一進一出」的單純管線 (Pipe)。這種概念不一定能輕鬆寫出程式碼,卻算是比較好的作法。如果想找出影響某段程式碼的原因時,也只要去檢查該段程式碼即可;所以也是絕佳的工程設計實例。我們因此不建議使用全域變數 (Global variable),而最好使用物件導向 (OO) 的設計,讓別人看不到「黑盒子」內部的狀態。如果所有事情都能獨立,就能更輕鬆的分析軟體。這表示你需要能保證記憶體安全 (Memory safe) 的程式語言。

某些具備記憶體安全的較高階語言就算速度不快,我也同樣愛用。其實很多時候你根本不在乎速度。如果你確實在意速度,就必須將相關部分隔離出去成為單一程序。

 

看到這裡,是否更了解網路上的某些安全概念了呢?請繼續看完《該如何寫出更好的軟體?─ 系列訪談之二 (下)》。

 

 

原文連結:How can we write better software? – Interview series, part 2 with Brian Warner

 

 

 

您可能也會喜歡

目前找不到相關文章

共 1 則讀者回應

  1. 參照: 該如何寫出更好的軟體?─ 系列訪談之二 (上) | 部落格 | Mozilla Taiwan

對此文章發表回應

你的電子郵件位址並不會被公開。 必要欄位標記為 *