AI構建的SaaS在第一位付費用户前我審計的內容
本文作者基於自己用AI構建SaaS的經驗,指出AI生成代碼在規模生產中的關鍵問題:缺乏機械性的拒絕表面。作者建議在SaaS上線前審計七項關鍵安全與可靠性措施,包括:邊界授權(而非處理器內部)、數據庫層深度防禦、AI調用的評估而非單元測試、每租户成本歸屬、提示注入的爆炸半徑、API密鑰安全和可觀測性。文章強調,這些結構性防禦比行為性提醒更有效。
本文以一個警示故事開篇:一個AI構建的MVP上線生產環境,兩週內便有客户讀取了其他客户的數據。原因是模型在十四個處理器中漏掉了一個租户隔離檢查。代碼看起來完全相同,測試全部通過,但代碼庫中沒有東西從機械層面上拒絕了這個錯誤。這揭示了核心問題:AI生成的代碼缺乏“拒絕表面”——即代碼本身機械地拒絕無效輸入或狀態的邊界。
作者使用Cursor和Claude Code在九個月內獨立構建了多租户SaaS Allset,基於此經驗,他提出了在迎來第一位付費客户前需要審計的七個領域:
- 邊界授權,而非處理器內部授權:不應依賴每個處理器內部的運行時檢查(模型可能遺忘),而應將授權變為類型。例如,
TenantAccess值只能由一個邊界函數構造,該函數執行數據庫查找。跳過此檢查的代碼無法編譯。Allset使用SpiceDB強制執行此規則。
- 數據庫層的深度防禦:即使有了類型化邊界,仍需第二道鎖。使用數據庫級別的強制措施,如PostgreSQL的行級安全(RLS)或DynamoDB的IAM條件。應用程序在連接邊界設置租户ID的會話變量,數據庫獨立拒絕不匹配的行。Allset在每個租户作用域的表上使用Aurora Postgres的RLS策略。
- 使用評估(evals)而非單元測試來測試AI調用:單元測試不適合隨機性的AI輸出。應使用評估——輸入數據集配以評分函數,在CI中運行。從20個評估開始,每次用户報告模型出錯時增加一個。這種基礎設施提供真正的信心,而快照固定(snapshot-pinning)每次模型更新都會失效。
- 每個模型調用的按租户成本歸屬:為每次模型調用打上租户ID、模型和用途的標籤。一個簡單的儀表盤就能顯示每個租户的每日成本。這在第一天只需五分鐘,但事後重構需要一週。沒有它,就無法明智定價或檢測失控循環。
- 提示注入的爆炸半徑:不要試圖完全阻止注入(不可能),而應限制代理工具在當前租户上下文中的作用域。例如,
db_query工具應使用租户作用域的憑證。跨越租户邊界的工具應結構上無法從單租户代理上下文中調用。
- API密鑰安全:使用臨時、作用域限定的密鑰,而不是長期密鑰。這限制了密鑰泄露時的損害。
- 可觀測性:實現指標、日誌和追蹤,特別是針對安全和成本異常。這確保你能快速檢測並響應問題。
作者強調,這些結構性防禦遠比行為性提醒(如“在CLAUDE.md中驗證租户訪問”)有效。代碼本身必須機械地拒絕錯誤行為。從一開始就構建這種拒絕表面,對任何追求生產可靠性的AI構建SaaS都至關重要。