6.2 安全開發生命週期與 Code Review#
把安全「左移」:在設計與開發階段解決#
6.1 的滲透測試是事後驗證。SDL(Security Development Lifecycle,微軟 2004 年因 Blaster 蠕蟲停機一個月而制度化)的洞見:
\[ \text{修復成本隨階段指數上升}: \text{設計} \ll \text{開發} \ll \text{上線後} \]
(本系列全書的反覆主題:「把錯誤往時間軸左端移」—— 型別系統、SQLx 編譯期檢查、以及現在的 SDL。)
SDL 全景#
flowchart LR
R[需求\n安全需求+合規] --> D[設計\n威脅建模(1.2)]
D --> I[開發\n安全編碼+審查]
I --> T[測試\nSAST/DAST/滲透(6.1)]
T --> DE[部署\n加固+掃描(4章)]
DE --> O[營運\n監控+回應(5.3/5.4)]
O -.回饋.-> R每個階段的安全活動:
| 階段 | 活動 | 本書工具 |
|---|---|---|
| 需求 | 個資盤點(5.2)、合規需求 | 檢查清單 |
| 設計 | DFD + STRIDE、資料分級 | 1.2 四問法 |
| 開發 | 編碼規範、code review、SAST | 本章 |
| 測試 | 單元測試含安全案例、DAST、滲透 | 6.1 |
| 部署 | 依賴掃描(4.2)、配置基線(2.4) | CI 檢查 |
| 營運 | 告警(5.3)、事件回應(5.4) | 手冊 |
安全的 Code Review#
普通 review 問「對不對」,安全 review 額外問「被濫用會怎樣」。檢查清單(按風險排序):
新端點檢查#
[ ] 輸入:提取器/驗證覆蓋所有參數?(前書 3.2, 3.3 白名單)
[ ] 認證:在保護組內?預設拒絕?(3.3)
[ ] 授權:owner 條件?角色檢查?(3.3 IDOR)
[ ] 限流:昂貴操作有限制?(3.4)
[ ] 輸出:無洩漏內部細節?(前書 2.4 錯誤處理)
[ ] 日誌:安全事件有記?無敏感明文?(5.3)
高危代碼模式(review 時全文搜尋)#
# 危險訊號搜索清單
grep -rn "innerHTML\|dangerouslySet" src/ # XSS(2.1)
grep -rn "exec\|eval\|system(" src/ # 命令注入(3.1)
grep -rn "query(.*+\|f\"" src/ # 字串拼接 SQL(3.1)
grep -rn "redirect(.*req\." src/ # 開放重導向(2.3)
grep -rn "process.env" src/ # 秘鑰使用點盤點(4.3)
工具化這些檢查(lint 規則、grep 進 CI)比「靠 reviewer 記住」可靠 —— 人會累,regex 不會。
自動化安全測試:SAST 與 DAST#
| 類型 | 時機 | 原理 | 工具 |
|---|---|---|---|
| SAST 靜態 | 寫碼時/CI | 分析源碼找危險模式 | Semgrep、CodeQL、cargo clippy+lint |
| DAST 動態 | 測試環境 | 黑盒打真實應用 | OWASP ZAP、nuclei |
| SCA 依賴 | CI | 對照 CVE 資料庫 | 4.2 audit |
Semgrep:可自訂的結構化搜索#
# 危險的 innerHTML 賦值
rules:
- id: unsafe-innerhtml
patterns:
- pattern: $EL.innerHTML = $X
message: "innerHTML 可致 XSS,使用 textContent 或 DOMPurify"
severity: ERROR
SAST 的天花板:誤報與「不懂業務邏輯」。實務配置為增量模式(只掃 PR 的 diff),把噪音壓到可執行。
威脅建模的輕量化實踐#
大型正式建模(1.2 四問法)不必每次全跑。輕量儀式:新功能 PR 描述中必填三行:
## 安全考量
- 輸入:接受哪些不可信資料?如何驗證?
- 授權:誰可以呼叫?如何確認?
- 資料:接觸哪些個資?記了什麼日誌?
讓安全思考成為流程的預設欄位 —— 對抗遺忘的不是記憶力,是表格(checklist 的社會工程)。
安全文化:最後的防線是人#
| 反模式 | 症狀 | 解方 |
|---|---|---|
| 安全=資安團隊的事 | 開發者不學不問 | 每人背基本清單(6.3 實戰) |
| 安全=延期藉口 | 「先上線再說」 | 增量修復承諾+自動化降低成本 |
| 責怪報告者 | 漏洞被隱瞞 | blameless(5.4)+ 獎勵發現 |
| 一次性的安全專案 | 補完就爛 | 持續的 CI 檢查+定期演練 |
\[ \text{安全的複利}: \text{每個 PR 的小檢查} \xrightarrow{\text{數年}} \text{整體安全水位} \]
習題#
- 把「高危代碼模式搜索」寫進 CI(Semgrep 或 grep 腳本),對現有專案跑第一次清掃。
- 為你的下一個功能 PR 建立安全三行範本,並在團隊試行一週記錄發現的問題。
- 比較 SAST 與 DAST 各自抓不到的漏洞類型,說明為何兩者都要。