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-secretsgitleaks 在 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:竄改 lsps 隱藏外部行為,最後只能 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)