重點摘要
大部分人的資安是「出事再補」。威脅建模(threat modeling)反過來 —— 在上線前,有系統地問每個環節「這裡會怎麼被打?」。我用一個叫 STRIDE 的框架,幫診所系統 ExClinCalc 盤出 24 個威脅、逐一對應到防護。這篇講 STRIDE 是什麼、怎麼用,以及它的限制。
為什麼要「事前」想威脅
醫療系統的資料一旦外洩就是不可逆的事件 —— 你沒辦法「收回」已經洩漏的病歷。所以我不想靠「上線後看有沒有出事」,而是在設計階段就把可能的攻擊列清楚。
問題是:漫無目的地想「會不會被駭」通常會漏。人腦想威脅容易只想到自己熟悉的那幾種。框架的價值就是給你一份「不會漏掉大類」的檢查表 —— STRIDE 就是這樣一份表。
STRIDE 是什麼
STRIDE 是微軟提出的威脅分類法,把攻擊分成六大類。每個字母是一類:
| 字母 | 威脅類型 | 白話 | 對應的資安目標 |
|---|---|---|---|
| S | Spoofing | 假冒別人的身分登入 | 身分驗證 |
| T | Tampering | 偷改資料 | 完整性 |
| R | Repudiation | 做了壞事卻抵賴 | 不可否認性 |
| I | Info Disclosure | 看到不該看的資料 | 機密性 |
| D | Denial of Service | 讓系統癱瘓 | 可用性 |
| E | Elevation of Privilege | 從小權限變大權限 | 授權 |
用法很簡單:對系統的每個重要環節(登入、每張資料表、每個 API),逐一問這六類威脅「會不會發生?怎麼防?」。六類跑一遍,就不容易漏掉整個大類。
我怎麼套用到 ExClinCalc
ExClinCalc 是一套六角色的診所系統。我對它的每個關鍵環節跑 STRIDE,總共盤出 24 個威脅。挑幾個最有代表性的講:
S(假冒身分)→ 有人偷到密碼冒充醫師
- 威脅:攻擊者拿到醫師帳密,登入看所有病人。
- 防護:密碼之外強制 TOTP 雙重驗證。光有密碼進不來,還要手機上那組 6 位數。
T(竄改)→ 有人繞過前端直接改資料庫
- 威脅:攻擊者不透過我的程式、直接對資料庫下指令改處方。
- 防護:權限規則寫在資料庫層(RLS),不是只寫在程式。就算繞過前端,資料庫自己還是擋。
R(否認)→ 醫師事後否認開過某張處方
- 威脅:出事時有人說「不是我做的」,而系統無法證明。
- 防護:敏感操作(登入、開處方、改病歷)由資料庫 trigger 自動寫入稽核軌跡(audit log),保留 90 天。這道紀錄在資料庫層觸發,應用層竄改不掉。
I(資訊洩漏)→ 金鑰不小心出現在前端
- 威脅:呼叫外部服務的高權限金鑰被寫進前端程式,任何人打開開發者工具就看到。
- 防護:金鑰只存在邊緣節點的執行環境秘密裡,永不進前端 bundle、git 歷史、log。
D(阻斷服務)→ 有人狂試密碼把系統打爆
- 威脅:自動化程式狂送登入請求。
- 防護:5 次失敗鎖定該帳號 30 分鐘(鎖 user 不鎖 IP —— 攻擊者沒密碼也觸發不了對別人的鎖定)。
E(提權)→ 護理師想拿到醫師的權限
- 威脅:低權限角色試圖存取高權限功能。
- 防護:每個角色能看/能做什麼,由 RLS 規則精確界定;沒有一條路徑能讓角色自己升級。
這個練習真正的價值
盤完 24 個威脅,最大的收穫不是「列出 24 條」這個數字,而是:
- 它逼我對每個環節都想過一遍,而不是只防我本來就會的那幾種。
- 它讓防護和威脅一一對得上 —— 我能說清楚「TOTP 是為了擋 S、RLS 是為了擋 T 和 E、audit log 是為了擋 R」,而不是「我加了很多資安功能」這種空話。
- 它產生一份可溝通的文件 —— 面試或口試被問「你怎麼確保安全」,我能拿出這張表,而不是臨場硬掰。
誠實說:威脅建模不等於安全
這一段很重要,不能誇大:
- 威脅建模是「找威脅 + 設計防護」,不是「證明沒有漏洞」。它幫你不漏大類,但想得到的深度取決於做的人。
- 它不等於滲透測試。我做了多角色帳號互測,但那是功能驗證,不是真人紅隊攻擊。
- 有些威脅我列了、但目前的防護是「已知但未做」。例如 TOTP 還沒有 backup code 機制(手機遺失的救援),這是我明確標記的待補項,不是假裝不存在。
威脅建模的誠實用法是:它讓我知道自己防了什麼、還沒防什麼 —— 這份清醒本身,比「號稱很安全」有價值得多。
延伸閱讀
- 為什麼我選擇 PostgreSQL Row Level Security ── 擋 Tampering 與 Elevation 的核心防線
- 被問到「你的系統架構長怎樣」,我會怎麼講 ── 這些防護分別落在架構哪一層
- ExClinCalc Case Study ── 完整的安全設計與截圖