危害控制階層(或如何防止工程師把正式環境搞垮)
原文由 Hillel Wayne 于 發布,訂閱此部落格
前幾天,一位機械工程師向我介紹了危害控制階層(Hierarchy of Controls,簡稱 HoC),這是職場安全中一個很重要的概念。1
為了保護人們免於危害,系統設計者應該盡量採用最有效的控制措施。也就是說,能消除就不要替代,能替代就不要只靠工程控制,以此類推。
那麼,我們能把危害控制階層套用到軟體工程上嗎?軟體環境和實體環境很不一樣,但或許有些概念值得借鑑。接下來,我們就來實際演練看看,把 HoC 套用到一個我當菜鳥工程師時搞出正式環境停擺的案例上。
問題
大約十年前,我當時想在正式環境上除錯一個問題。我同時開著一個已透過 SSH 連進正式環境的 shell 和一個本地開發用的 shell,兩個視窗並排,結果切錯了分頁,在錯誤的地方執行了錯誤的指令。
就這樣,我上了一堂新課:如何從備份還原正式環境的資料庫。
在製程安全中,危害指的是讓傷害得以發生的任何事物:梯子讓墜落成為可能,液壓機讓手指被壓碎成為可能。以我的案例來說,危害可能是那個擁有無限制權限的正式環境 shell,它讓正式資料遺失成為可能。而具體的傷害則包括直接把資料庫刪掉(就像我幹的那樣),或是在資料庫上執行 delete 查詢。我會用這兩種傷害來討論不同類型的危害控制措施。
先說幾個前提
HoC 原本是設計來保護人免於被機器傷害,而不是保護機器免於被人傷害!我發現大部分概念套用得還不錯,但在個人防護具(PPE)這塊就卡住了。
而且,要把某個措施歸到哪一類,也有很多可以爭辯的空間。在寫這篇文章的過程中,我也在試著釐清這些類別之間質性的差異。以下都只是我這個十足門外漢的個人解讀。
最後,HoC 關注的是預防傷害,而不是傷害發生後的復原。像是「定期備份資料庫」或「事故後進行事後檢討」這類軟體的最佳實務,就不屬於這個階層的討論範圍。
各層控制措施
以下引言皆出自 OSHA 的 HoC 工作表。
消除
消除能確保危害不再存在。
消除是最直接的預防方式:根本不要有危害。OSHA 的各種教材都用同一個例子:想減少墜落傷害,就不要讓勞工在高處作業。在我們的案例裡,我們可以把正式環境整個拿掉,或是把資料庫拿掉。
這兩個做法都不太實際,而大多數 HoC 的資料也很快就會指出,真正的消除往往是做不到的。我們之所以會和危險物質共事,正是因為它們對流程來說不可或缺。「消除」最有用的地方,似乎在於提醒我們自問:「這個危險的東西真的必要嗎?」必要的危害無法消除,但非必要的就可以。在 2020 年被淘汰之前,Adobe Flash 一直是最大的資安漏洞來源之一。要保護自己最簡單的方法是什麼?把 Flash 移除掉。
替代
替代指的是替換材料或流程以降低危害。
和消除不同,替代是保留危害,但降低它的危險程度。如果危害是有毒農藥,我們可以改用低毒性的農藥;如果是吵雜的機器,就換成比較安靜的機型;如果是記憶體不安全的語言,就改用 Rust。
以我們的問題來說,我能想到幾種可能的替代做法。我們可以把正式環境的 shell 換成權限較弱的 shell。想像一下,如果某台「正式」伺服器只能看到資料庫的唯讀複本,那麼 delete 查詢就起不了作用,就算把資料庫刪掉也不會真的遺失資料。另一種做法是改用不可變的紀錄系統,像是事件溯源(event sourcing)模型。這時「刪除資料」會變成「在資料庫中新增一筆刪除紀錄」。不小心刪錯了,只要再補上一筆「還原」紀錄就能輕易復原。
工程控制
工程控制透過防止危害接觸到工作者來降低暴露風險,但同時仍讓工作者能夠完成工作。
工程控制並未改變危害本身的危險性,而是透過額外的實體設計來降低事故的風險與嚴重程度。做法有很多種:我們可以減少工作者需要暴露在危害中的機會、降低危害引發事故的可能性,或是讓事故比較不會造成傷害。

比起消除或替代,工程控制有更多發揮創意的空間。以下是一些工程控制的點子:
- 監控與可觀測性做得更好,我可能根本就不需要登入正式環境。
- 權限政策設得更好,我可以禁止在該環境中刪除資料庫,或是要求必須持有特殊的開發者金鑰才能執行這類操作。
- 或者,資淺工程師根本就不該擁有正式環境的存取權限。如果我想除錯,就必須請更有經驗的人來操作。
- 自動登出可以避免讓閒置的正式環境終端機一直開著,等著被我不小心用 Alt-Tab 切過去。
有些工程控制比另一些更有效。一個有名的「效果很弱」的控制是確認對話框:
$ ./drop_db.sh
This will drop database `production`.
To confirm, type y: [y/N]這種做法的問題在於,如果我在本地環境很常執行這個指令,就會養成直接按 y 的肌肉記憶,等到在正式環境也這麼做時,就會毀了自己的一天。
一個有名的「效果很強」的控制則是「輸入完整名稱」的確認對話框:2
$ ./drop_db.sh
This will drop database `production`.
To confirm, type `production`:就算有肌肉記憶,記住的也會是輸入 local,這樣反而會擋下這個危險操作。如果你試著在 GitHub 上刪除一個儲存庫,就能看到實際的例子:

OSHA 有些工程控制的例子,在我看來比較像替代,反之亦然。我用來區分兩者的經驗法則是:工程控制可能會失效,替代則不會。如果權限設定錯誤,實際上根本沒擋住我刪除資料庫呢?相對地,如果環境只能存取到唯讀複本,我就沒辦法憑空把寫入用的複本毀掉。希望如此啦。
不過,這個經驗法則並不完美!把 C 換成 Rust 算是替代,但 Rust 的某些保證還是可以透過 unsafe 來繞過。
行政控制
行政控制會改變工作方式,或透過提供相關流程、訓練或警示來讓工作者獲得更多資訊。
工程控制改變的是技術,行政控制改變的是人。那些改變人與技術互動方式的控制,可能屬於任一類;我曾為「輸入完整名稱」的確認對話框到底算是行政控制還是工程控制而長篇爭論過。兩種說法其實都有道理。
以下是一些行政控制的點子:
- 公司規定資淺人員不得連線到正式環境
- 播放訓練影片,讓大家了解刪掉資料庫有多容易
- 一次只開一個終端機視窗
- 規定只有在與另一位開發者結對時才能連線到正式環境
- 減少工時與趕工,讓工程師不要那麼睡眠不足
- 定期對營運問題進行兵棋推演。
OSHA 還把「自動警示」歸為一種行政控制。例如「登入正式環境時會在 Slack 上發送一則訊息」就屬於這類。
在階層中,行政控制的位階比工程控制低,原因有幾個。第一,工程控制是內建在系統裡的,而行政控制是社會性的,需要每個人都接受訓練才會遵守。第二,在我看過的所有 HoC 範例中,要破壞工程控制需要花力氣,而要遵守行政控制才需要花力氣。如果趕時間、忘記了、注意力不集中等等,就可能不會遵守。
有些行政控制可以提升為工程控制。像是「資淺工程師絕對不能 SSH 連進正式環境」的公司規定,屬於行政控制,仰賴每個人都遵守規則;而「資淺人員根本沒有正確的 SSH 金鑰」的設定,則是工程控制。
個人防護具
個人防護具(PPE)包括用來保護工作者的衣物與裝置。
這是最底層的控制:提供裝備給人員以保護他們免於危害。PPE 可以降低受傷的風險(如果我穿著反光背心,就比較不容易被堆高機撞到),或是降低傷害的嚴重程度(安全帽不會阻止東西掉到我頭上,但可以緩衝衝擊)。
我認為 PPE 是在軟體中最不適用的控制。首先,HoC 原本是要保護人,而在軟體中我們想保護的是系統。那麼,軟體的 PPE 到底是人戴著以防止對系統造成損害,還是系統戴著以防止被人損害呢?一個「人員 PPE」的例子,可能是把正式環境的終端機設成紅色背景、開發環境設成藍色背景。我能想到的所有「系統 PPE」例子,嚴格來說都算是工程控制。
第二,PPE 之所以不是工程控制,是因為工程控制會改變危害本身,而 PPE 是介於人與危害之間的第三方。但在軟體中,任何介於人與軟體之間的東西本身也是軟體!就連「改用 Postman 而不是 curl」這類做法,也比較像是工程與行政的混合,而不是「真正的」PPE。
我能想到兩個 PPE 比較說得通的場景。第一個是資安領域,像是安全瀏覽器、雙重驗證(2FA)和密碼管理器,都算是某種 PPE。第二個則是用來減少軟體開發者常見職業傷害的 PPE,例如腕隧道症候群、背痛和眼睛疲勞。這些情境之所以「說得通」,是因為它們涉及的是人員受傷,而這正是 HoC 當初設計的目的。
PPE 在階層中的位階比行政控制更低,是因為員工需要紀律與訓練才能有效使用 PPE。在現實世界中,PPE 往往笨重又不舒服,而且有 90% 的時間其實根本沒有在保護你(因為你並未處於危險中)。一篇關於營建事故的論文發現,在研究的事故中,有 65% 受傷的勞工當時並未配戴 PPE。要讓 PPE 發揮最大效益,就必須訓練人員並強制要求使用,也就是說,本身就已經需要有行政控制措施到位。
關於 HoC 的其他筆記
控制措施應該組合使用
越高層級的控制越能消除危險,但也越難實作。越低層級的控制效果越差,但更靈活、成本也更低。
軟體天生就很適合做工程控制
我還在釐清這個想法究竟是什麼,但大致是這樣:在現實世界中,人們透過「自然介面」與危害互動,基本上就是把自己當作空間中的一個物體。如果我在操作液壓機,預設情況下我就是可以把手伸進去。我們必須在系統中額外加入實體物件來防止傷害,或是訓練人們如何正確使用這些實體。
在軟體中,所有的介面都是人為建構出來的:危害來自於我們額外加入了能夠造成傷害的能力。我們更容易用不同的方式來建構介面,以降低造成傷害的可能性,或是以強制限制的形式來落實行政控制。
這件事在我之前的一份工作中就曾發生。我們的使用模式意味著在離峰時段部署新版本最安全。「只能在離峰時段部署」是一種行政控制。於是我們在部署腳本中加了一行程式碼,檢查執行的時間,如果是在尖峰時段就直接報錯。這就是把行政控制轉化為工程控制。3
而且,現實世界中的工程控制非常昂貴,這也是人們選擇行政控制和 PPE 的一大原因。但軟體比起實體系統能夠更快、更便宜地被修改,這讓工程控制在軟體中更有效。
(我認為替代也有類似的道理。)
控制措施本身也可能成為危害來源
如果你去看我上面連結的 OSHA 工作表,會在這裡看到一個有趣的欄位:

任何可能的控制方法都可能為工作場所帶來新的風險。大量的行政警示會造成警示疲乏,讓人們錯過真正關鍵的警報。禁止人員進入倉庫,可能會迫使他們繞道經過另一種危害。反光背心可能會被機器捲入。必須從整體來考量整個系統的安全性:局部的安全改善可能會在其他地方造成問題。
在軟體中我們也看得到這種情況。Lorin Hochstein 有一場演講提到,Netflix 的許多停機事故其實是由那些原本用來保護系統的軟體所引起的。
那麼,我的控制措施又可能帶來哪些新危害呢?
- 改用只能附加的資料庫可能需要大量的再訓練與軟體修改,反而製造更多出錯和新錯誤的空間
- 過於嚴格的存取政策可能會在我試圖修復線上問題時拖慢速度,讓問題變得更嚴重
- 過多的行政控制可能會讓人們只是「照表操課」、自動駕駛般地走流程,反而對可能的危險失去警覺。
我發現,要辨識出控制措施可能帶來的新危害,比辨識現有的危害要困難得多。
以上就是 HoC 的精華。我覺得這是個很棒的概念!
如果你喜歡這篇文章,歡迎訂閱我的電子報!我每週都會在那裡發表新的文章。
我為企業提供形式化方法的培訓,讓軟體開發更快、更便宜、也更安全。歡迎點此了解更多。
隨機一篇部落格
留言
登入後參與討論