Lovable 會在發佈時運行基礎安全掃描,但自動掃描不能證明業務授權正確。
尤其是 Supabase 項目,表上“啓用了 RLS”與“策略不會越權”是兩件事。
先畫清楚身份和數據邊界
列出匿名用戶、登錄用戶、管理員和後臺任務。
再列出每張表的所有者字段與租戶字段。
|
|
沒有明確歸屬字段的表,很難寫出可靠策略。
確認每張業務表都啓用 RLS
在 Supabase SQL Editor 查詢真實狀態。
|
|
新增表最容易漏掉 RLS。
把結果保存爲上線審計附件。
策略必須分別覆蓋四種操作
SELECT、INSERT、UPDATE 和 DELETE 的風險不同。
允許讀取自己的行,不代表應該允許修改所有字段。
插入時使用 WITH CHECK 驗證新行歸屬。
更新時同時檢查舊行可見性與新行合法性。
刪除操作通常需要更嚴格角色。
多租戶策略不要只比較 user_id
團隊產品通常依賴 membership 表。
策略應驗證當前用戶屬於目標 organization。
還要檢查成員狀態是否有效、角色是否允許操作。
被停用成員不應繼續讀取舊租戶數據。
邀請記錄不能等價於正式成員。
用兩個賬號做越權測試
創建租戶 A 用戶 Alice 和租戶 B 用戶 Bob。
讓 Alice 創建一條可識別測試記錄。
Bob 嘗試列表查詢、按 ID 查詢、更新和刪除該記錄。
不要只測 UI。
在瀏覽器開發者工具中複製請求,替換資源 ID 後重放。
所有越權請求應返回空結果或授權錯誤。
Service Role Key 絕不能進入前端
它會繞過 RLS,必須只存在於受控服務端。
搜索倉庫和構建產物:
|
|
如果曾經提交過,不是刪掉文件就結束。
應立即輪換密鑰,並檢查 Git 歷史與部署日誌。
Anon Key 可以公開但權限不能寬鬆
Supabase anon key 本來用於客戶端。
它的安全性依賴 RLS 與數據庫權限。
不要因爲它可公開,就忽略被濫用後的請求成本。
對高消耗接口增加速率限制與驗證碼。
Storage 也需要獨立策略
檢查 bucket 是 public 還是 private。
私有文件使用短期 signed URL。
對象路徑最好包含可信的用戶或租戶前綴。
不要只從客戶端文件名推導所有權。
嘗試把另一個租戶的對象路徑傳給下載接口。
Edge Function 驗證令牌而非相信參數
函數應從 Authorization header 驗證用戶。
不要接受請求體裏的 user_id 作爲身份依據。
管理員動作在服務端重新查詢角色。
日誌中不要打印完整 JWT、Cookie 或支付信息。
數據庫函數檢查 SECURITY DEFINER
|
|
SECURITY DEFINER 函數以所有者權限運行。
必須固定 search_path,限制 execute 權限,並審查動態 SQL。
沒有必要時改回默認的調用者權限。
前端隱藏按鈕不是授權
Lovable 生成的頁面可能根據角色隱藏管理按鈕。
攻擊者仍能直接調用 API。
所有權限必須在數據庫策略或服務端再次執行。
UI 判斷只改善體驗,不構成安全邊界。
發佈前執行負面測試
測試未登錄訪問。
測試過期 token。
測試普通用戶調用管理員接口。
測試跨租戶 UUID。
測試批量接口混入一條無權記錄。
測試上傳超大文件和僞造 MIME 類型。
測試已刪除賬號的舊 token。
負面用例全部通過,才說明策略不僅覆蓋正常路徑。
發現問題後的處理順序
先收緊策略或暫停受影響功能。
再輪換泄露的密鑰。
檢查審計日誌確認是否已被利用。
修復後用兩個租戶重新測試。
最後才重新發布前端。
不要把安全問題只交給新的自然語言提示“再優化一下”。
最終檢查表
-
所有業務表 RLS 狀態已導出。
-
四類數據庫操作都有明確策略。
-
多租戶授權通過 membership 驗證。
-
Service Role Key 未進入客戶端或 Git。
-
Storage bucket 與對象策略已測試。
-
Edge Function 獨立驗證身份與角色。
-
SECURITY DEFINER 函數逐個審查。
-
兩賬號越權測試覆蓋讀寫刪。
-
密鑰輪換與事件響應路徑可執行。
自動掃描適合發現常見配置錯誤;多租戶業務規則仍需要人工設計和對抗性測試。
Supabase 安全資料
用 SQL 查看現有策略而不是隻看界面
|
|
導出結果後逐表覈對。qual 決定哪些舊行可見,with_check 決定寫入後的新行是否允許存在;只寫其中一個,可能造成讀寫規則不對稱。
一個多租戶讀取策略的審查思路
|
|
真實策略還要結合角色與業務需求。審查時確認 organization_id 有索引,否則每次查詢都可能掃描 memberships,安全策略會變成性能瓶頸。
防止用戶修改所有權字段
允許用戶更新標題時,不應同時允許他把 owner_id 或 organization_id 改成其他值。可以限制更新列,或者在 WITH CHECK 中要求所有權保持合法。
API 測試應顯式發送所有權字段,而不是依賴前端表單不展示它。攻擊者可以直接構造 JSON 請求。
邀請流程的競態條件
團隊邀請至少包含隨機 token、過期時間、目標郵箱、組織和狀態。接受邀請時在一個數據庫事務裏檢查並標記 token 已使用。
同一個邀請鏈接併發提交兩次,只能創建一個 membership。已經撤銷或過期的邀請必須失敗,不能因爲用戶已登錄就跳過檢查。
Storage 上傳後進行二次驗證
客戶端的 Content-Type 可以僞造。服務端或異步任務讀取文件頭,確認真實格式,並對圖片、PDF 等類型設置獨立大小限制。
公開 bucket 不放身份證、合同和用戶導出文件。私有 bucket 的 signed URL 設置短有效期,日誌不記錄完整簽名 URL。
Edge Function 的 CORS 不是授權
CORS 只控制瀏覽器能否讀取跨域響應,不能阻止 curl 或服務端請求。函數仍需驗證 JWT、租戶成員關係和具體操作權限。
預檢請求只返回必要方法和 Header。不要爲了消除瀏覽器報錯而使用任意 origin 加憑據組合。
備份中也包含敏感數據
Supabase 備份、SQL dump 和本地種子文件使用與生產數據相同的保護級別。下載到開發電腦前先確認磁盤加密與訪問權限。
恢復演練使用隔離項目。恢復完成後立即輪換測試環境中隨數據帶入的 token、Webhook secret 與第三方憑據。
上線後的持續檢查
監控 RLS 拒絕數量、異常批量讀取、Storage 流量和 Edge Function 錯誤率。單次拒絕通常是正常輸入錯誤,短時間內遍歷大量 UUID 則可能是越權探測。
每次新增表、bucket 或函數都重新執行安全清單。不能因爲第一次上線審計通過,就認爲之後生成的所有功能自動繼承正確策略。