生產環境就緒檢查清單
每個條目說明應檢查的事項。根據 CLAUDE.md 中定義的階段層級,應用適合項目階段的條目;如果沒有定義階段,則推斷階段(原型、MVP、生產或規模化)並說明。在審查中,將不適合該階段的條目標記為「尚不適用」,並說明觸發其變得相關的條件。
1. 安全性與存取控制
- 授權: 在每個端點和存取的每個物件上,伺服器端檢查權限,而不僅是在登入時(防止 IDOR 和 BOLA)。對於 Supabase、Firebase 或類似後端,必須啟用並測試行層級安全性或安全規則。
- 輸入驗證: 在每個信任邊界,使用架構庫(Zod、Pydantic 或同等工具)驗證類型、長度、格式和範圍。用戶端驗證僅用於用戶體驗,絕不能用於安全。
- SQL Injection: 僅使用參數化查詢或 ORM 綁定。對於動態識別碼(例如排序欄位),使用允許清單。
- XSS: 依賴框架的跳脫機制。避免在未受信任的資料上使用
innerHTML、dangerouslySetInnerHTML和v-html,或使用經過驗證的函式庫(如 DOMPurify)進行清理。添加內容安全策略。 - CSRF: 對於基於 Cookie 的會話,使用 SameSite Cookie 加上 CSRF Token 或對狀態變更請求進行來源檢查。永遠不要透過 GET 請求變更狀態。
- CORS: 允許清單中指定確切的來源。絕不反映任意來源或允許帶有憑證的萬用字元。CORS 不是存取控制。
- SSRF: 當伺服器擷取使用者提供的 URL 時,允許清單中的目的地,封鎖私有、回送和鏈路本地地址(IPv4 和 IPv6,包括雲端後設資料 169.254.169.254),並在重新導向和 DNS 解析後重新檢查。
- 機密管理: 從環境變數或機密管理器中載入機密。它們永遠不應出現在程式碼、日誌、容器映像檔或 git 歷史記錄中,任何已洩露的機密都應輪換。
- IAM: 對每個人員、服務和 Token 套用最小權限原則。每個環境和每個服務使用不同的憑證,絕不在應用程式中使用 root 或管理員金鑰。
- OAuth: 使用經過驗證的提供者或函式庫,而非自訂驗證。對於瀏覽器和行動用戶端,使用帶有 PKCE 的授權碼流程、精確的重新導向 URI 匹配、狀態驗證以及最小範圍。
- JWT 輪換: 使用短效的存取 Token、帶有重複使用偵測的輪換重新整理 Token,以及透過金鑰 ID (
kid) 和 JWKS 輪換的簽署金鑰。始終驗證簽名、演算法、發行者、受眾和過期時間。 - 密碼與會話安全性: 使用 Argon2id 或 bcrypt 對密碼進行雜湊處理。將會話 Cookie 設定為 HttpOnly、Secure 和 SameSite。在帳戶具有價值的場景提供 MFA。
- TLS: 在所有地方提供 HTTPS,具有自動憑證續約功能,最低要求 TLS 1.2(偏好 1.3),並啟用 HSTS。永遠不要停用憑證驗證。
- 傳輸中加密: 加密內部流量以及公共流量,包括服務、資料庫、快取和佇列連線。
- 靜態加密: 加密資料庫、磁碟、備份和物件儲存,金鑰存放於 KMS。對於高度敏感數據,考慮欄位級加密。
- 安全標頭: 設定 Content-Security-Policy(包括針對點擊劫持的 frame-ancestors)、Strict-Transport-Security、
X-Content-Type-Options: nosniff和 Referrer-Policy。 - WAF: 在公開的生產應用程式前放置一個具有受管規則集的 Web 應用防火牆。
- DDoS 防護: 依賴提供者防護(Cloudflare、AWS Shield 或平台預設值),加上速率限制和自動擴展上限,以防止攻擊導致無限帳單。
- 供應鏈安全: 在 CI 中執行依賴項漏洞掃描(npm audit、pip-audit、Dependabot 或類似工具)。驗證每個新套件是真實的、名稱正確且持續維護的。
- 檔案上傳: 根據內容(而非副檔名)檢查類型、限制大小、以隨機名稱儲存於物件儲存中,並透過短期有效的簽署 URL 提供私有檔案。
- 稽核日誌: 記錄敏感操作(驗證事件、權限變更、資料匯出、資金移動)的執行者、操作內容和時間,並儲存於僅附加的儲存中。
- 隱私與 PII: 收集最少資料,了解個人資料存放位置,避免將其記錄在日誌中,定義保留期限,並在 GDPR 或 CCPA 等法律適用時支援刪除和匯出。
2. 資料與資料庫
- 資料庫索引: 對將成長的資料表中用於篩選、連接和排序的欄位建立索引,包括外鍵。避免會減慢寫入速度的重複索引。
- 查詢最佳化: 對緩慢或頻繁的查詢,使用
EXPLAIN檢查執行計畫。僅選擇需要的欄位,並避免在 WHERE 子句中將索引欄位包裹在函數內。 - N+1 查詢: 尋找每次查詢一個項目的迴圈。將其替換為 Join、預先載入或批次處理。
- 連線池: 根據資料庫限制調整池大小。在無伺服器架構中,使用連線池(PgBouncer、RDS Proxy 或提供者的連線池),因為每個執行個體都會開啟自己的連線。
- 交易: 將必須全部成功或全部失敗的多步驟寫入包裝在一個交易中,並慎重選擇隔離級別。
- 約束: 在資料庫中使用 NOT NULL、UNIQUE、外鍵和 CHECK 約束來強制完整性。僅靠應用程式檢查會因競爭條件而失效。
- 分頁: 對每個列表端點和查詢進行分頁,並設定頁面大小上限。對於大量或不斷變化的資料,偏好使用游標(鍵集)分頁。
- 金錢與時間: 以整數最小單位或 decimal 類型儲存金錢。以 UTC 儲存時間戳記,僅在顯示時進行轉換。
- 唯讀副本: 僅在讀取操作超載主要資料庫時才添加,並處理複製延遲,特別是用戶讀取自己寫入的資料時。
- 複製: 了解複製是同步還是非同步,以及故障轉移可能遺失多少資料。
- 分割: 對非常大的資料表(通常按時間)進行分割,以保持索引和維護的可管理性,並通過刪除分割區來過期舊資料。
- 分片: 將其視為在索引、快取、複製和垂直擴展之後的最後手段。選擇一個能避免熱點和跨分片查詢的分片鍵。
- 資料庫遷移: 保持遷移檔案有版本控制、經過審查、在部署中自動化,並在可能的情況下可逆轉。為了零停機時間,使用「擴展與收縮」策略:先在一個版本中添加,然後回填資料、切換,最後在後續版本中移除。在進行破壞性變更前進行備份。
- 架構版本控制: 對資料合約(資料庫架構、事件載荷、API 架構)進行版本控制,以便在部署期間,新舊程式碼可以同時運行。
3. 並發與分散式系統
- 競爭條件: 尋找「檢查後再執行」的程式碼(餘額、庫存、唯一用戶名、優惠券兌換)。使用原子更新、約束、交易或鎖定來修復。
- 執行緒安全: 同步或消除跨執行緒、工作程序和異步任務的共享可變狀態。模組級別的全局變數通常會跨請求共享。
- 樂觀鎖定: 對於低競爭記錄,在更新時檢查版本欄位或 ETag,並在衝突時返回 409 或 412。
- 悲觀鎖定: 對於高競爭的關鍵區段,使用
SELECT ... FOR UPDATE,並保持鎖定時間短暫。 - 死結: 以一致的順序獲取鎖定,保持交易短暫,並在死結錯誤時重試。
- 分散式鎖定: 僅用於跨進程的協調,使用會過期的租約和柵欄令牌。在可能的情況下,偏好使用資料庫約束或佇列。
- 分散式交易: 避免跨服務的兩階段提交。盡可能在單一資料庫內保持交易邊界。
- Saga 模式: 對於跨服務的工作流程,連結本地交易與補償動作,並使每個步驟都具有冪等性。
- CAP 定理: 在網路分割期間,系統必須在一致性或可用性之間做出選擇。根據功能決定:餘額和庫存需要一致性,而動態消息和計數器可以容忍過時資料。
- 最終一致性: 在可接受的情況下,設計 UI 和邏輯以處理過時讀取,並使更新最終收斂。
- 領導者選舉: 當恰好一個執行個體必須執行操作(排程器、單例工作程序)時,使用租約或平台原語,絕不寫死一個執行個體。
- 網路分割: 假設任何呼叫都可能中途失敗,或成功但無回應。使用逾時、冪等性和調解機制進行設計。
- 時鐘偏差: 絕不依賴跨機器的時鐘進行排序或正確性。使用資料庫時間戳記、序號或邏輯時鐘,並在令牌過期檢查中允許微小誤差。
- 服務發現: 透過 DNS、平台或註冊表解析服務,絕不使用寫死的 IP。
4. 韌性與容錯
- 逾時: 對每個對外呼叫(HTTP、資料庫、快取、佇列、LLM API)設定連線和請求逾時,使其適合呼叫者自身的截止時間。
- 重試: 僅對暫時性故障(逾時、連線錯誤、429、502、503、504)在冪等操作上進行重試,並限制嘗試次數。避免同時在每一層進行重試,這會成倍增加負載。
- 指數退避: 使用帶抖動的指數退避,並遵循
Retry-After標頭。 - 斷路器: 在重複錯誤後停止呼叫故障的依賴項,快速失敗並使用備用方案,並探測恢復狀況。
- 冪等性: 為可能被重試的操作(付款、訂單、Webhook 處理器、任務)提供一個冪等鍵或自然鍵,使重複操作不會產生額外影響。
- 背壓: 限制佇列、緩衝區和並發量。當負載過重時,卸載負載或返回 429 或 503,而不是接受無限制的工作。
- 隔艙: 隔離資源(不同的池或工作程序),使一個緩慢的依賴項無法耗盡所有資源。
- 優雅降級: 決定當依賴項宕機時,哪些功能仍然可用,例如快取資料、唯讀模式或暫時隱藏某個功能。
- 優雅關機: 收到
SIGTERM訊號時,停止接受新工作,完成正在進行中的請求和任務,然後關閉連線。 - 健康檢查: 為負載平衡器或平台暴露一個輕量的健康檢查端點。
- 存活與就緒探測: 存活探測僅用於檢測卡住的進程,不應依賴外部服務,否則一次資料庫小故障就會重啟所有服務。就緒探測定義一個實例是否應接收流量,並可以檢查依賴項。
- 故障轉移: 了解主要資料庫、可用區或提供者發生故障時會發生什麼。在重視正常執行時間的情況下自動化此流程,並進行測試。
5. 訊息傳遞、背景工作與即時通訊
- 訊息佇列: 將緩慢、可重試或突發性的工作(電子郵件、媒體處理、第三方呼叫)移出請求路徑,放入一個有工作程序的佇列中。
- 傳遞語義: 假設至少一次傳遞,因此消費者必須具有冪等性。除非系統保證每個鍵的順序,否則不要假設順序。
- 死信佇列: 將耗盡重試次數的訊息路由到 DLQ,並附帶警報和重播路徑。絕不默默地丟棄它們或永遠重試。
- 發布/訂閱: 用於扇出到多個獨立消費者,使用定義的事件架構和所有權。
- 事件驅動架構: 當解耦的價值超過除錯成本時採用。將事件視為版本化的合約,並保持請求在事件之間可追蹤。
- 交易型 Outbox: 當資料庫寫入後必須發布事件時,在一個交易中同時寫入兩者(一個 outbox 表格)並非同步轉發,這避免了雙寫問題。
- Cron 任務: 使排程任務具有冪等性,可以安全地執行兩次或重疊執行,一次僅限一個實例執行,並監控遺失或失敗的執行。
- WebSocket: 在連線時進行驗證、發送心跳、使用退避重新連線,並計畫多個實例(共享發布/訂閱或黏性會話)。
- 伺服器發送事件: 對於單向伺服器到用戶端的串流,如通知、進度和 LLM Token 串流,優先於 WebSocket。
- 長輪詢: 在 WebSocket 和 SSE 不可用時用作備用方案,設定逾時和連線數限制。
- Webhook: 對於傳入的 Webhook,驗證簽名 (HMAC)、拒絕過時的時間戳以停止重播、快速確認並非同步處理,並根據事件 ID 去重。對於傳出的 Webhook,簽署載荷、使用退避重試,並對事件格式進行版本控制。
6. 流量、邊緣與網路
- 速率限制: 對公共、驗證和昂貴的端點(登入、註冊、密碼重置、OTP、LLM 呼叫)按用戶、API 金鑰和 IP 進行限制。返回 429 和
Retry-After。 - 負載平衡: 在經過健康檢查的實例之間分發流量。保持應用伺服器無狀態,以便任何實例都可以服務任何請求。
- 反向代理: 在代理處終止 TLS、壓縮資料,並強制執行主體大小和逾時限制。僅信任來自已知代理的
X-Forwarded-For,以防止用戶端 IP 被偽造。 - API 閘道: 當存在多個服務或公共 API 時,集中處理驗證、速率限制、路由和驗證。單一應用程式通常不需要。
- CDN: 通過 CDN 提供靜態資源和媒體,使用較長的快取生命週期和內容雜湊檔案名稱。
- DNS: 在遷移前降低 TTL,盡可能將記錄作為代碼管理,並預期傳播延遲。
- TCP 與 UDP: 預設使用基於 TCP 的協議。僅對需要低延遲且能容忍丟包的流量(即時媒體、遊戲)使用 UDP,並在應用層進行處理。
- HTTP/2 與 HTTP/3: 在邊緣或 CDN 啟用它們,以實現多路複用和更快的連線。這通常是配置問題,而非應用程式代碼。
- gRPC: 用於需要嚴格合約或串流的內部服務呼叫,每次呼叫都設定截止時間。瀏覽器需要 gRPC-Web 或閘道。
7. 快取
- 快取: 僅在衡量需求後進行快取,並為每個快取定義鍵、TTL 和受眾。絕不將用戶特定或依賴權限的資料以通用鍵儲存在共享快取中。
- 邊緣快取: 明確設定
Cache-Control,將個人化回應標記為 private 或 no-store,並在允許一定程度上過時資料的情況下使用 stale-while-revalidate。
…(原文截斷,此為翻譯結果)