// docs / baas security / firebase if-true explainer
Firebase allow read, write: if true 解释:它做什么以及如何修复
allow read, write: if true; 是生产中最常见的单一 Firebase 配置错误。它是创建新数据库时 Firebase 控制台建议的测试模式默认值、AI 编码工具从文档重新生成的规则,以及向互联网上任何人开放整个 Firestore 数据库的规则。本文精确解释语法、展示此规则有效时攻击者看到的内容,并给出四个适合不同用例的逐步更严格替换。
逐行解释语法
一个完整的 Firestore 测试模式规则文档是六行:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}解码:
rules_version = '2';选择 v2 规则引擎 (当前)。较旧的 v1 规则已弃用。service cloud.firestore将块限定到 Firestore。Realtime Database 使用不同的基于 JSON 的语法;Cloud Storage 使用service firebase.storage。match /databases/{database}/documents绑定特殊的(default)数据库 (大多数项目只有一个)。match /{document=**}是递归通配符。**匹配任意深度的任意路径。与{document}结合,这捕获每个集合中的每个文档 — 一个 match 子句统治整个数据库。allow read, write: if true;是规则主体。read和write都被允许;条件if true嘛,永远为真。read涵盖get和list操作;write涵盖create、update和delete。
净效果:任何拥有 Firebase 项目 ID 和正确 SDK 的客户端都可以读取或写入任何集合中的任何文档。不需要身份验证。不强制速率限制。
Firebase 为何将此作为默认值
Firebase 希望你在创建项目后的前 30 秒内开始编码。替代方案 — 在任何读写工作之前让你编写正确的规则 — 会阻塞入门。所以控制台在你创建数据库时提供两个选项:生产模式 (拒绝一切,你自己写规则) 或测试模式 (30 天允许一切)。大多数开发者点击测试模式,然后忘了再去看。较旧的项目有 30 天计时器;当前项目有无自动过期的不确定 if true 规则。
结构性问题:AI 编码工具在显示测试模式规则的文档、教程和 Stack Overflow 答案上训练。当你问 Cursor 或 Claude Code「如何设置 Firebase」时,答案常常包含完全相同的 allow read, write: if true 块,仿佛它就是生产规则。AI 不知道 — 也没有被提示去知道 — 此规则对生产不安全。
攻击者看到什么
Concretely, an attacker who knows your Firebase project ID (it ships in every deployed app's configuration) can list every collection and read every document with plain, unauthenticated requests to Firebase's public REST API.
Once the collections are listed, every document in them can be read. Nothing slows this down, because if true rules accept anonymous traffic.
在写入路径上:带 {fields} 的单次 POST 创建新文档。攻击者可以用垃圾污染你的集合,污损从 Firestore 读取的用户面页面,或将你的数据库用作免费消息代理 — 你的使用账单飙升,你调查,账单解释了问题。
四个生产安全替代方案
选择匹配你应用数据模型的替代方案。所有四种都假设你有用户身份验证 (Firebase Auth 或任何发行 Firebase ID 令牌的提供商):
选项 1:用户拥有的文档
最常见的 SaaS 模式。文档位于 /users/{userId}/... 下,只有所有者可以接触它们。match /users/{userId}/{document=**} { allow read, write: if request.auth != null && request.auth.uid == userId; }
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}选项 2:每个文档上的所有者字段
当文档位于扁平集合中 (未嵌套在用户 ID 下) 时,存储一个 owner_uid 字段并检查它。match /posts/{postId} { allow read: if resource.data.public == true || resource.data.owner_uid == request.auth.uid; allow write: if request.auth.uid == resource.data.owner_uid; }
match /posts/{postId} {
allow read: if resource.data.public == true
|| resource.data.owner_uid == request.auth.uid;
allow write: if request.auth.uid == resource.data.owner_uid;
}选项 3:多租户组织隔离
适用于具有组织范围数据的 B2B SaaS。在每个文档上存储 org_id 字段,并对照用户的自定义声明检查它。allow read, write: if request.auth.token.org_id == resource.data.org_id;。需要在注册期间通过 Firebase Admin SDK 设置自定义声明。
allow read, write: if request.auth.token.org_id == resource.data.org_id;
选项 4:只读公共内容
适用于营销内容、公共个人资料、产品目录 — 任何真正公开读取但仅管理员写入的内容。match /products/{productId} { allow read: if true; allow write: if request.auth.token.admin == true; }。admin 自定义声明只在管理员账户上设置。
match /products/{productId} {
allow read: if true;
allow write: if request.auth.token.admin == true;
}快速审计查询
在修复前,检查 if true 是否真的生效。打开 Firebase 控制台 → Firestore → Rules 并搜索 if true。如果你在注释之外的任何地方找到它,就有一项开放规则发现。同一 UI 中的规则模拟器让你在本地重放攻击者的请求 — 粘贴一个匿名 GET /users/somebody 并确认模拟器返回 允许。
External confirmation: run a FixVibe scan against your production URL. FixVibe checks your Firestore, Realtime Database, and Storage rules from the outside and reports what an attacker would find — independent of what the Firebase Console shows.
常见问题
if true 和 if request.auth != null 之间有什么区别?
if true 允许匿名访问 — 互联网上的任何人。if request.auth != null 需要任何登录用户,这更好但仍然错误:你应用的任何用户都能读取其他每个用户的数据。生产规则必须通过 request.auth.uid == resource.data.owner_uid 或类似方式限定到特定用户或组织。
Firebase 会自动让 if true 规则过期吗?
较旧项目 (2023 年前) 有 30 天计时器,会将 if true 规则转换为 if false。当前项目没有 — 规则会无限期存续,直到手动替换。如果你的项目在 2023 年前创建,规则看起来没问题,请仔细检查:计时器可能已将它们翻转为 if false,这会阻塞你自己的应用。
我可以使用未来日期时间戳检查作为安全网吗?
不能 — 时间戳条件不是安全控制。它在未来日期使开放规则过期,这意味着在那个日期之前攻击者拥有完全访问权。而你会忘记这个日期。用基于身份验证的规则替换 if true,而不是时间限制的规则。
如果我的应用真的是公开读取 (博客、产品目录) 怎么办?
那么明确地写 allow read: if true; allow write: if false; 仅在公共集合上 — 而不是数据库中的每个集合。每个集合使用单独的 match 子句,并且绝不在可写规则上使用递归 {document=**} 通配符。
后续步骤
Run a FixVibe scan against your production URL — it confirms whether if true is currently exploitable from the public internet. For how the scanner covers Realtime Database and Storage as well, see Firebase rules scanner. For the equivalent class of misconfiguration on Supabase, read Supabase RLS scanner.
