Sam Newman 在本章開宗明義說自己「不是應用程式安全專家」,目標是成為自覺的不專業者(conscious incompetent)——清楚自己不懂什麼。本章從通用開發者/架構師/維運的視角整理需要建立的基本共識;真正進入專案時仍需專家參與。
微服務帶來一個有趣的兩難:
- 負面:更多資料跨網路流動、更多基礎設施 → 攻擊面變大
- 正面:更多邊界可以做縱深防禦、更小的爆炸半徑 → 可以更安全
兩股力量並存,本章的目的是讓你站在天平的有利那一邊。
核心原則#
最小權限(Principle of Least Privilege)#
只授予必要的最小權限、且僅限必要的時間。
- 微服務若只需要讀取資料庫,就只給 read-only credential
- 憑證有時效 → 即使被盜也很快失效
- 限制服務之間能互相呼叫的範圍
縱深防禦(Defense in Depth)#
想像 Dover 城堡:建在山上、兩道城牆、最內層還有 keep(堅固塔樓)。一道牆破了還有下一道。
微服務天然提供更多縱深防禦的機會:服務切細、跑在不同網段、混合不同技術棧(避免單一 zero-day 一次打穿)。
安全控制的三類#
- 預防(Preventative):阻止攻擊發生(加密、SSO、密鑰管理)
- 偵測(Detective):發覺攻擊正在發生/已發生(IDS、應用防火牆)
- 回應(Responsive):攻擊發生中/後協助處理(自動重建、備份還原、溝通計畫)
三類缺一不可。
自動化#
微服務數量多 → 手動操作不可能持續正確。自動化能:
- 用最小權限分配給特定腳本
- 加快撤銷、輪替密鑰
- 減少人為失誤
- 協助偵測異常
把安全內建在交付流程中#
安全不該是後置工序——和「易用性」「測試」「維運」一樣,要從一開始就嵌入。
Jonny Schneider 的比喻:把安全當「Do you want fries with that?」(要不要加薯條?)就是把它當配菜——但沒有安全的軟體本來就不是合格的主餐。
工具範例:
- ZAP(Zed Attack Proxy):仿真攻擊網站,受 OWASP 啟發
- Brakeman:Ruby 靜態分析
- Snyk、GitHub code scanning:偵測有已知漏洞的第三方相依
把這些工具整合進 CI 是基本要求。但記住:它們只能抓「局部」問題;系統層級的安全仍要靠整體設計。
NIST 五大功能(The Five Functions)#
美國 NIST 把資安活動切成五大功能,作者推崇其全貌觀:
- Identify(辨識):誰可能來攻擊?想要什麼?哪裡最脆弱?
- Protect(保護):保護關鍵資產
- Detect(偵測):察覺攻擊已發生
- Respond(回應):察覺到問題後該做什麼
- Recover(復原):事件後重建系統並學到教訓
「前門裝得銅牆鐵壁,後門卻沒鎖」——很多人把所有時間花在 JWT、mTLS 之類技術細節,卻忽略整體威脅模型(threat model)。
作者親見:某公司激辯辦公室是否該裝 CCTV 攝影機,吵了很久才有人提醒「正門那把鎖早就壞了,每天進門根本不用鑰匙」。
延伸閱讀:Adam Shostack《Threat Modeling: Designing for Security》。
應用程式安全的基礎#
憑證(Credentials)#
兩大類:
- 使用者憑證:人和操作者用的帳號密碼、多因子裝置
- 秘密(Secrets):服務跑起來需要的 TLS 憑證、SSH key、API key、資料庫連線字串等
Verizon 2020 資料外洩報告:80% 駭客事件牽涉憑證竊取——釣魚、暴力破解。
對使用者憑證的當代建議#
Troy Hunt 整理 NIST 與英國 NCSC 的最新建議:
- 用密碼管理器
- 用長密碼(不需要怪怪的「規則」)
- 不需要強制定期變更——這個建議多年來常被誤用,反而讓使用者選更弱的密碼
Code Spaces 案例:駭客拿到 AWS 根帳號 → 把資料、備份全部清光。「Rock Solid」的 SVN/Git 託管商從此倒閉。
另一案例:客戶 API key 外洩,駭客拿去開昂貴 EC2 跑 cryptocurrency mining,三天 $10K 才被發現。
秘密的生命週期#
- 建立(Creation)
- 配送(Distribution)
- 儲存(Storage)
- 監控(Monitoring)
- 輪替(Rotation)
工具:
- Kubernetes 內建 Secrets(功能簡單但夠用)
- Hashicorp Vault(開源 + 商業版):可動態產生時效性的資料庫憑證;搭配
consul-template可即時更新本地設定檔 - 雲端:AWS Secrets Manager、Azure Key Vault
輪替(Rotation)#
- 頻繁輪替能限制憑證外洩的影響
- AWS 有許多組織採用「短時效 API key」:每次操作前產生,有效期不到一小時——即使不小心 commit 到公開 GitHub 也無濟於事
- 輪替帶來部署痛點,但這是值得付出的成本
撤銷(Revocation)#
- 確認外洩時,需要立即撤銷而非等下次排程輪替
- 微服務需要能重讀新值——若採 Vault 等工具且服務做動態載入,撤銷後即時生效
- 已習慣輪替的團隊,撤銷流程通常自然到位
掃描金鑰外洩:用
git-secrets、gitleaks在 commit hook 中阻擋私鑰被推上 repo;GitHub 也會自動掃描。
限制範圍#

Figure 11.1:限制憑證範圍以縮小被誤用的影響

Figure 11.2:每個 Inventory 實例擁有獨立的資料庫憑證
每實例獨立憑證 → 可逐實例輪替、撤銷;也方便追溯哪個實例造成奇怪的查詢。需自動化(如 Vault)才實際可行。
修補(Patching)#
Equifax 2017 資料外洩:Apache Struts 已知漏洞——修補檔釋出數月後 Equifax 仍未更新——導致 1.6 億人個資外洩、$700M 和解金。

Figure 11.3:基礎設施由多層構成,每一層都需要修補

Figure 11.4:使用託管 Kubernetes 可以大幅縮小自己負責的修補範圍
- 容器看似不可變,但內含作業系統——半年沒動的容器代表半年沒修 OS patch
- 工具:Aqua(容器掃描)、Snyk、GitHub code scanning
備份(Backups)#
備份就像用牙線——很多人說自己有做,實際做的卻少很多。
Code Spaces 案例提醒:備份要存在與主系統隔離的位置。同帳號、同地區的備份不算備份。
薛丁格備份#
「Schrödinger Backup」:在你真的還原它之前,你不知道那是不是真的能用的備份。
解法:把「定期還原備份」做成日常流程——例如用備份建構效能測試環境,自然就驗證了還原能力。
重建(Rebuild)#
- 攻擊發生後,最快的回應常是整台機器抹掉重建
- 作者親遇 rootkit:竄改
ls、ps隱藏外部行為,最後只能 reinstall 整台 - 自動化部署 + 良好備份還原 = 可隨時重建
- 如果你經常重建(比如每次部署都用容器),重建就跟日常操作一樣
平日做的事,緊急時也能做。把容器化部署做好,就是最好的災難復原演練。
隱式信任 vs 零信任#
隱式信任(Implicit Trust)#
「網路內」的服務互信——多數組織預設這樣做,但很多時候只是因為沒意識到風險。一旦邊界被突破,內部全裸。
零信任(Zero Trust)#
「Jill, we’ve traced the call—it’s coming from inside the house!」
——電影《When a Stranger Calls》
零信任不是工具或產品,是心態:假設環境已被入侵——
- 所有 inbound 呼叫都要驗證
- 所有資料儲存要安全
- 所有金鑰要妥善保管
- 所有敏感資料傳輸要加密
真正落實零信任後,可以做出反直覺的決策:
「你可以允許從網際網路直接連進內部服務,因為你把『內網』和『公網』視為同樣不可信任。」
——Jan Schaumann
是光譜不是二元#
不必非黑即白。可以依資料敏感度分區:

Figure 11.5:MedicalCo 依資料敏感度把微服務部署到不同分區
MedicalCo 案例:把資料分成 Public / Private / Secret 三級,微服務跑在對應分區(zone)。Secret zone 採零信任,Public 較寬鬆。微服務只能向上呼叫(Secret → Private → Public),不能向下。
保護資料#
傳輸中(In Transit)#

Figure 11.6:傳輸資料的四個關注點
四大關注點:
- 伺服器身分:你連到的真的是聲稱的那個嗎?(HTTPS / TLS 解決)
- 客戶端身分:發出請求的真的是聲稱的那個服務嗎?(mutual TLS / API key 解決)
- 資料可見性:傳輸過程資料會不會被竊聽?(TLS 加密解決)
- 資料是否被篡改:傳輸途中能不能被修改?(TLS 或 HMAC 解決)
mutual TLS 過去因工具難用而少見,現在 Vault、service mesh(如 Istio、Linkerd)讓憑證配送變得相對簡單,在零信任環境下幾乎是預設選項。
靜態(At Rest)#
不管前面再怎麼防,資料落地時也要設防。原則:
- 用業界成熟方案:別自己手工寫加密;訂閱所選函式庫的安全公告
- 密碼用 salted hashing:絕不可明文存
- 挑目標而非全加密:全加密看似簡單,但運算負擔高、schema migration 複雜——找重點欄位/重點表加密
- 節儉(Datensparsamkeit):能不存的就不存——「沒存就不會被偷,也沒人能要求你交出」
- 用戶 IP 是否要全位址保留?把最後幾位改成 x 行不行?
- 金鑰本身的儲存:別把金鑰存進跟資料一起的資料庫——用獨立 vault
- 備份也要加密:production 加密了備份也得加密
最佳實踐:第一次看到資料時就加密,只在需要時才解密,並且絕對不再存。
認證與授權#
- 認證(Authentication):你是誰?
- 授權(Authorization):你能做什麼?
- 主體(Principal):被認證的對象——人或服務
服務對服務認證#
- mutual TLS(兼具加密與雙向認證)
- API key + 請求簽章
人類認證#
- 多因子認證(Multi-Factor Authentication, MFA):密碼 + 手機 App / SMS / 硬體 token(YubiKey)/ 生物特徵
- 重要服務(如 source code 存取)幾乎必備 MFA
單一登入(SSO)#
- 主體 → 身分提供者(Identity Provider, IdP)認證 → IdP 告訴服務提供者主體身分
- 常見 IdP:Google OpenID Connect、企業內 LDAP / Active Directory、Okta(hosted SAML)
- OpenID Connect(基於 OAuth 2.0)已壓倒 SAML 成為主流;SAML 是 SOAP-based、複雜
SSO 閘道(Gateway)#

Figure 11.7:使用閘道集中處理 SSO
- 把 SSO 重導與 IdP 握手放在閘道,避免每個微服務重做
- 下游服務透過 HTTP header 或 JWT 拿到主體資訊
- 小心:閘道做太多事就成為單點故障與耦合中心
- 也別因閘道擋住認證就鬆懈下游服務的縱深防禦
細粒度授權#
- 閘道做粗粒度(「未登入禁入」「STAFF 才能進客服」)
- 細粒度授權留給服務本身——「這個 call center 員工能不能退超過 $50?」
- 避免把細粒度規則放進 IdP:作者見過
CALL_CENTER_50_DOLLAR_REFUND這種 group——把服務邏輯外洩到目錄服務、難以維護 - 偏好以組織結構為基礎的粗粒度 role
Confused Deputy 問題#

Figure 11.8:Confused deputy 攻擊情境示意
- 已登入的客戶可以串改 URL請求別人的訂單嗎?
- 上游已認證不等於下游可以無腦信任
- 解法:把細粒度授權判斷推到擁有功能的服務(Order 服務自己判斷「這個訂單真的屬於這個使用者嗎」)
- 集中式上游授權違反獨立可部署性——上線新功能還要改閘道設定
JSON Web Token(JWT)#
當下解決「把使用者身分傳給下游服務」的最常見方案。
- 一段 JSON payload + 簽章(可選擇加密)
- 三段式 base64 字串:header.payload.signature
- 公開 claim 名稱(如
exp過期時間)由標準定義
範例 payload:
{
"sub": "123",
"name": "Sam Newman",
"exp": 1606741736,
"groups": "admin, beta"
}使用流程#

Figure 11.9:閘道為單次請求生成 JWT 並傳給下游服務
常見模式:客戶端用 OAuth token 呼叫閘道 → 閘道為每筆請求生成短時效 JWT → 傳給下游 → 下游驗證簽章並讀取 claim。
挑戰#
- 金鑰管理:下游怎麼拿到驗章用的公鑰?怎麼處理輪替?Vault 是常用解
- 長流程的過期問題:訂單從付款到出貨可能歷時數天,token 該設多久?常見做法是流程中段不再依賴 token(已交付給內部 worker 處理)
- token 太大:作者見過音樂版權系統需要 10,000 個欄位才能描述授權——此時改用「JWT 存少量基本資料 + 額外查資料庫」的混合模式
小結#
- 安全是整體性的工作——不是裝幾個 SDK 就好
- 從威脅模型出發,再決定哪些控制要做
- 縱深防禦:預防 + 偵測 + 回應,每層都不可少
- 微服務切細既擴大攻擊面,也提供更多縱深防禦機會——關鍵是有意識地利用後者
- 「機械化」操作(自動化、可重建、頻繁輪替)是現代安全工程的根基
- 推薦延伸閱讀:Laura Bell 等《Agile Application Security》(O’Reilly)