昨天,我們完成了 Vibe Guard 的安全基線。使用者可以登入並建立專案,Firestore Security Rules 也會限制使用者只能存取自己的資料。
今天要反過來做:刻意加入三個常見問題,建立 Production Readiness Agent 的第一組測試答案。
請勿部署:今天的程式碼故意不安全,只能使用假帳號與假資料,在 Firebase Local Emulator Suite 中操作。程式也會拒絕在非 localhost 網域執行。

三個問題不是彼此獨立。過度寬鬆的授權讓攻擊者取得別人的文件,文件又包含不必要的 Email,而不安全的畫面輸出會把惡意內容交給瀏覽器解析。Production 事故經常就是多個小錯誤串在一起。
Day 4 的規則會比較文件中的 ownerId 與登入者 UID。今天把規則改成:
match /projects/{projectId} {
allow read, write: if request.auth != null;
}
這條規則只回答「使用者有沒有登入」,沒有回答「使用者能不能操作這筆專案」。因此任何登入者都能讀寫 projects Collection 中的所有文件。
前端查詢也從只讀取自己的專案:
query(
collection(db, "projects"),
where("ownerId", "==", user.uid)
)
改成讀取全部專案:
query(collection(db, "projects"))
前端的 where 不是授權控制。即使畫面仍只查詢自己的資料,使用者也能修改瀏覽器程式或直接呼叫 Firestore API。真正的防線必須位於 Security Rules。
新增專案時,我們故意把登入者 Email 一起寫入:
await addDoc(collection(db, "projects"), {
name,
launchGoal,
ownerId: auth.currentUser.uid,
ownerEmail: auth.currentUser.email,
createdAt: serverTimestamp()
});
Vibe Guard 顯示專案清單不需要 Email。只保存 ownerId 已足以判斷擁有者。多存一份 Email 會增加資料外洩範圍,也可能在使用者變更 Email 後留下過期資料。
「資料庫中有 Email」本身不一定是漏洞。真正的問題是:這個欄位對功能沒有必要,而且寬鬆的授權規則讓其他登入者可以讀取它。
安全基線使用 textContent,瀏覽器只會把專案名稱當成文字。今天改用字串組合與 innerHTML:
item.innerHTML = `
<strong>${project.name}</strong>
<p>${project.launchGoal}</p>
<small>Owner: ${project.ownerEmail}</small>
`;
現在專案名稱與上線目標會被當成 HTML 解析。即使輸入欄位限制長度,也沒有改變資料是不可信輸入的事實。
為了安全示範,我們只使用不執行 JavaScript 的標記:<mark>這不是純文字</mark>
如果儲存後文字出現黃色標記,就證明瀏覽器把輸入當成 HTML,而不是普通文字。請不要輸入會執行程式碼或載入外部資源的內容。
步驟一:建置並啟動 Emulator
cd /media/mickey/777/ithome/demo-app
npm run build
npm run emulators
開啟 http://127.0.0.1:5000。頁面上方會顯示紅色警告,提醒這是刻意不安全的版本。
步驟二:使用第一個帳號建立專案
1. 建立 user1@example.test。
1. 新增專案,名稱輸入 User 1 Project。
1. 確認畫面顯示標記效果與 Owner Email。
1. 登出
步驟三:使用第二個帳號讀取資料
未來 Gemini 不能只回答「Security Rules 不安全」。一項合格 Finding 至少要包含位置、前提、操作與影響。
嚴重度不能只看程式碼長相。AUTH-01 讓任意登入者跨帳號取資料,是已經可以重現的授權問題。PRIV-01 的影響來自不必要的資料欄位與越權讀取組合。INPUT-01 已證明存在 HTML Injection,但是否能形成可利用的 XSS,還要根據瀏覽器行為與輸入情境進一步驗證。
這些問題會保留在 Demo 中,作為後續 Agent 的固定考題。Day 7 與 Day 8 會分別深入授權和個資外洩,再比較修正前後的差異。
明天,我們會第一次把這個專案交給 Gemini。我們將在 Google AI Studio 設計 Code Reviewer Prompt,觀察模型能抓到哪些問題,又會產生哪些沒有證據的警告。
Firebase, Writing conditions for Cloud Firestore Security Rules
OWASP, A01:2021 Broken Access Control
MDN, Element: innerHTML property