Firebase Security Rules:别再让你的数据库敞开大门
Firebase Web 应用直接从浏览器读写 Firestore、Realtime Database 和 Cloud Storage,所用的配置对象任何人都能看到。Security Rules 是决定请求是否被允许的唯一依据。停留在测试模式、或被放宽到允许一切的规则,会把你的整个数据库暴露在互联网上。
这是什么
Security Rules 是一种小型策略语言,在 Google 的服务器上针对每一次读写进行评估。每个 match 块对应一个路径——集合、文档或存储文件夹——allow 语句则说明在什么条件下允许哪些操作,条件中会用到 request.auth(谁在请求)和 request.resource.data(他们想写入什么)。
Firebase Web 配置(包括其中的 apiKey)只用于标识你的项目;它不是密钥,本身也不授予任何访问权限。正因如此,规则才如此重要:任何访客都能用你的配置初始化 Firebase SDK,并直接在自己的浏览器控制台里查询你的数据库。
为什么重要
Firestore 的测试模式在到期日之前允许所有读写。期限一到、应用出错时,常见的“修复”是 allow read, write: if true——这会让每个文档都对全世界可读可写。暴露的 Firebase 数据库是大规模数据泄露的常见来源,而且极易被发现和导出。
只检查 request.auth != null 的规则也好不了多少:任何人都能创建账户(通常还是匿名的),然后读取所有用户的数据。如果不校验写入,用户还能修改本不该由他们控制的字段——比如在自己的资料上设置 role: "admin"。
如何修复
默认拒绝,按集合逐一授予访问权限。在下面的示例中,每个用户只能读写 users 中属于自己的文档,其他任何内容都无法访问。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
// Every other path is denied by default.
}
}限制用户可以修改的字段,使他们无法给自己提权或篡改由服务器管理的数据。affectedKeys().hasOnly() 会拒绝任何触及其他字段的更新。
match /users/{userId} {
allow update: if request.auth.uid == userId
&& request.resource.data.diff(resource.data)
.affectedKeys().hasOnly(["displayName", "photoURL"]);
}在规则中搜索与宽泛 allow 组合使用的 match /{document=**}、if true,以及会过期的测试模式时间戳。别忘了 Cloud Storage 和 Realtime Database 有各自独立的规则文件——它们也要锁住。
使用 Firebase 控制台中的 Rules Playground,或配合 @firebase/rules-unit-testing 使用 Emulator Suite,分别以未认证用户和另一个已登录用户的身份执行读取。一个快速的外部检查是发送未认证的 REST 请求——如果它返回了文档,说明该集合是公开的。
curl "https://firestore.googleapis.com/v1/projects/<project-id>/databases/(default)/documents/users"常见问题
我的 Firebase apiKey 是密钥吗?
不是。Firebase Web 配置中的 apiKey 用于标识你的项目,本就是要发送到浏览器的。请用 Security Rules 保护你的数据,并在 Google Cloud 中把该 key 限制为应用实际使用的 API,避免它被拿去调用其他计费的 Google 服务。
request.auth != null 就够了吗?
很少够用。它只能证明请求者已登录——不能证明数据属于他们。请将 request.auth.uid 与文档所有者进行比较,或检查一个用户无法自行设置的角色。
AppSafe 会检查我的 Firebase 规则吗?
AppSafe 不会查询你的 Firebase 项目,因此无法评估你的规则——请使用 Rules Playground 或上面的 curl 检查。但它会标记在你的 JavaScript 中发现的 Google API key(AIza… 格式),因为 Maps 或 Gemini 等计费服务也使用同样的格式。对于 Firebase Web 配置来说这是正常的;只要确保该 key 已受限即可。