Lovable 上生產安全嗎:訪問控制審查問題
Lovable 很適合快速原型,但生產系統的問題不是能不能跑,而是誰能審查訪問控制。RLS、前端過濾和安全掃描都重要;真正的邊界必須在服務端可見、可強制、可簽字。
TL;DR: Lovable 能把原型和早期產品做得很快,這一點值得承認。風險在於:決定「誰能讀到使用者資料」的訪問控制,常常落到 Supabase RLS、SQL 策略和生成程式碼裡,而負責上線的人未必能審查這些邊界。前端過濾 .eq('owner', user.id) 能讓 demo 表現正確,但它只是請求層面的便利,不是安全邊界。公開披露的 CVE-2025-48757 和相關掃描報告,說明錯誤 RLS 配置確實能導致真實資料暴露。Lovable 後續加入了安全掃描和企業控制,這些有價值;但掃描器降低風險,不等於把生產責任轉移出去。「能跑」和「安全」仍然是兩個不同的主張。
讓我把這個失敗的確切形狀展示給你看,因為「vibe coding 有風險」這句話毫無用處,關鍵全在細節裡。
一位創始人描述了一個帶使用者賬戶的應用。Lovable 把它做出來,接上 Supabase,然後上線。每個使用者只看到自己的記錄。創始人用兩個賬戶測試;表現完美。在 demo 裡,它是正確的。
現在開啟瀏覽器的網路面板——那個非開發者從不會開啟的東西——看看應用實際發出的請求:
// 前端把查詢「限定」到當前使用者:
const { data } = await supabase
.from('customers')
.select('*')
.eq('owner', user.id) // 看起來像是安全邊界。它不是。
那個 .eq('owner', user.id) 是一個過濾條件——一個請求上的引數。任何人都可以開啟網路面板,複製那個端點,然後去掉過濾條件重新發出去。本該阻止他們拿到所有人那些行的,是表上的行級安全策略。公開漏洞案例裡的錯誤配置,常常長這樣:
-- 本應充當邊界的那條 RLS 策略:
create policy "Enable read access for all users"
on public.customers for select
using (true); -- ← 對每一行、每一個呼叫者都求值為 true
using (true) 的意思是:每一個已認證的呼叫者都可以讀到每一行。 這條策略存在。它是開著的。而它什麼都不保護。這個應用只在恰好一種配置下看起來安全——前端碰巧請求的那一種——而在任何人換一種問法的那一刻就敞開了。這不是抽象擔憂;公開披露的 CVE-2025-48757 討論的正是這類 RLS 與客戶端請求邊界混淆的問題。
過濾不是邊界
這就是整個概念,值得把它點名出來,因為你一旦看見就再也無法當作沒看見:過濾是請求層面的便利;邊界是無論請求如何、都在服務端被強制執行的東西。 demo 能跑,靠的是過濾。資料安全,只有在存在邊界時才成立。兩者從外部看是無法區分的——它們都讓兩個測試賬戶看到正確的東西——而這恰恰是為什麼一個非開發者無法靠使用一個應用來分辨它是安全的還是已暴露的。
被 Lovable 賦予構建應用之力的那個人,按照產品自身的設計,正是最沒有裝備去讀懂 using (true) 與真正的 using (auth.uid() = owner) 之間差別的那個人。能力和理解被拆開了。這個拆分,既是產品的魔法,又在同一筆之下是它的責任。
拆解那個顯而易見的反駁:「Lovable 加了一個安全掃描器」
平心而論,這個批評擊中了 Lovable,他們也作出了回應——一個安全掃描器,一個帶 SSO 和審計日誌的企業層。所以公正的問題是:這難道沒把口子堵上嗎?
看看掃描器能解決什麼、不能解決什麼。Lovable 的安全掃描會檢查資料庫配置、RLS 規則、雲專案設定和常見誤配置,這當然有價值,也比沒有強得多。但檢查是否存在風險訊號和證明每條訪問路徑都符合業務許可權不是一回事。後者需要理解資料模型、角色、記錄歸屬和異常路徑。掃描器可以幫你發現問題、降低漏檢機率,卻不能替你承擔「這套訪問控制已經可以上生產」的簽字責任。
而那些企業級控制——SSO、組織審計日誌——管的是人們如何登入 Lovable,不是AI 在你應用裡寫了什麼 RLS。它們是真實的、好的,而且與此正交。缺口不在 Lovable 的企業姿態。缺口在於:AI 為每個應用生成的那套訪問邏輯,對那個唯一為它負責的人來說是讀不懂的。
解釋 170 起洩露的那個數字:驗證的不對稱
這裡真正值得記住的,不是某個具體數字,而是驗證成本的不對稱。比較兩項成本:
- 構建成本(把應用做出來):一句話。按設計,實際上是零——這正是整個賣點。
- 驗證成本(確認它是安全的):讀每張表生成的 RLS,對每一條 API 路徑進行推理,把過濾與邊界區分開。這是專家工時,而且是構建者並不具備的一項技能。
當構建成本坍縮到幾分鐘,而驗證成本仍停留在專家工時時,一個非專家很容易跳過驗證——因為他做不了,而應用看起來已經完成了。把這個模式放大到一批應用裡,你得到的就不只是幾起偶發洩露,而是一種結構性風險。問題不只屬於 Lovable;任何一個讓非專家生成自己讀不懂的訪問控制的工具,都繼承同樣的不對稱。
Lovable 恰恰正確的地方——以及那句誠實的限定
對於一個原型、一個落地頁、一個駭客松作品、一個內部用完即棄的東西、一個融資 demo——任何沒有真實人物的資料坐在應用背後的場景——Lovable 都很出色,而且幾乎肯定比任何更講規矩的東西(包括我們)都快。當沒有任何東西需要被暴露時,驗證的不對稱不花你一分錢。用它,並享受它。
還有那句讓這篇文章不至於成為一篇抹黑稿的誠實限定:這是結構性的,不是 Lovable 的缺陷。任何一個為非專家坍縮了構建成本、卻把驗證留在專家成本上的工具,都繼承同樣的不對稱——而 Lovable 正在積極地試圖收窄它。要點不是「Lovable 不好」。要點是:對於生產資料,「構建者讀不懂訪問控制」這件事就足以讓它出局,無論構建器上印的是誰的標誌。
這條線是鮮明的:在真實人物的資料開始活在它背後的那一刻——客戶、患者、員工——「能跑」就不再是任何東西的證據,「我看不見那條邊界」也就不再是一種便利,而成了那個風險本身。
一個你三十秒就能做的測試
忘掉功能清單。去問那個把它上線的人:
「開啟網路面板,拿到那條資料請求,去掉過濾條件,然後把它發出去。你拿回來的是隻有你自己的那些行——還是所有人的?」
如果他做不了這個測試,或者看不懂它,或者答案是「所有人的」,那麼這個應用至少還沒有完成生產級安全審查——無論它看起來多麼精緻,無論某個掃描器給它打了個對勾。
ObjectStack 的立場
ObjectStack 把那個導致洩露的拆分反轉過來。訪問控制不是構建者讀不懂的生成 SQL;它是被宣告出來、可讀的後設資料——作為物件一個屬性的 read: owner == current_user——而且它是一條執行時在服務端強制執行的邊界,所以去掉一個前端過濾什麼都改變不了。當 AI 提議改動「誰能讀到什麼」時,它會作為一份非專家真的能批准的 diff 浮現出來(「這會讓 customers 對所有人可讀——確認嗎?」),而絕不會是一個你本得讀 SQL 才能抓到的、悄無聲息的 using (true)。而且因為它是可自託管的、並坐落在你本來就在執行的系統上,敏感資料不會悄悄落到某個你無法檢視的地方。
我們不會在「到第一個 demo 的時間」上贏過 Lovable,而對於原型我們也不會去試。真正要緊的主張,是在真實資料一旦牽涉其中的那一刻才生效的:一個 AI 構建的應用,它的安全邊界必須對那個為它擔責的人是可見的。看不見邊界,不等於邊界不存在;但在生產系統裡,它意味著你還沒有完成可簽字的審查。