4.1 安全避坑:密钥泄露、规则裸奔与数据导出风险

安全这一节,我不打算讲理论,只讲三个真实发生过、且至今仍在反复发生的事故。它们的共同点是:出事之前,当事人都不觉得自己做错了什么。

事故一:把配置当成了私密信息

新项目接入 Firebase,控制台会给一段前端配置对象,里面有 apiKey、projectId 这些字段。很多人的第一反应是:这是钥匙,必须藏好。于是想方设法把它塞进环境变量、混淆进构建产物,甚至为此搭出一套复杂的注入机制。

真实情况是:这段配置本来就会跟着前端代码到达每一个用户的浏览器,打开开发者工具就能看全。它不是私密信息,公开是设计使然。

那真正的防线在哪?两处。第一处是安全规则:Firestore 和 Cloud Storage 的每一次读写都要过规则这一关,配置只负责告诉客户端数据库在哪,能不能进由规则说了算。第二处是身份认证侧的配置,比如登录方式的授权域名、验证码类能力的滥用防护,这些才需要认真管。

理解了配置可见不等于不安全,你会砍掉大量无用的藏钥匙代码,把精力放回真正该花的地方——规则设计。

事故二:规则裸奔

最经典的一幕:开发期间为了图省事,规则写成全放开模式,读写一概放行。项目顺利上线,规则忘了收。数据库就这样裸奔在公网上,直到某天被扫到。

后果通常按顺序发生:先是数据被整库爬走,接着要么被要挟,要么被灌进一堆垃圾数据,最后账单和口碑一起崩。别以为测试库就安全——爬虫不在乎库里是不是假数据,垃圾写入和产生的费用在乎。

正确姿势其实就三句话:

  • 默认拒绝:规则的底座永远是全拒绝,每个集合只在确有需要时按条件放开。
  • 按需放开:给规则做加法之前先问一句,这个开放的最小边界是什么,还能不能再收一收。
  • 上线前评审:把规则检查当成发版动作的一部分,像看代码 diff 一样看规则 diff。

一份可以直接抄进流程的上线前清单:

  • [ ] 没有任何一条规则包含无条件放行
  • [ ] 涉及用户数据的读写都校验了登录态与归属
  • [ ] 写操作校验了字段类型、大小和取值范围
  • [ ] 规则文件已提交版本控制,本次变更有 diff 可查
  • [ ] 规则单测在模拟器中全部通过

事故三:私钥进了前端或公开仓库

和配置对象不同,Admin SDK 的服务账号私钥是真正的钥匙:拿到它就等于拿到绕过全部安全规则、直接读写整个数据库的管理员权限。它只应该出现在服务端。

但事故总在发生。有人图省事,把服务端初始化代码直接搬进前端,把管理端 SDK 打包给了浏览器;有人把含私钥的密钥文件提交进了公开仓库。后者尤其危险——有机器人专门盯着新提交做扫描,从私钥上线到被利用,时间以分钟计。

正确的做法并不复杂:

  • 私钥只放环境变量或密钥管理服务,永不进代码仓库
  • 仓库配置忽略规则,把密钥文件挡在提交之外
  • 给服务账号分配最小权限,只授予业务真正需要的角色
  • 一旦怀疑泄露,立即在控制台撤销并轮换密钥,不要心存侥幸

数据导出风险与定期审计

还有一类风险没有具体的钥匙,却同样致命:只要某条读规则开得太宽,任何人都能分页遍历整个集合,把数据一点点导干净。规则评审时不要只盯着写操作,读的边界同样要一条条过。

规则也不是写完就完的东西。我的习惯是把规则审计做成周期性动作:每月看一次规则 diff 和各集合的引用关系;每季度在模拟器里跑一遍规则单测;有条件的话,把规则评审纳入新人上手的必读流程。规则变更是 diff 最小、后果最大的变更,值得多看一眼。

收尾一张表:

事故 后果 预防
把配置当私密信息 精力浪费在藏不该藏的东西上,真正的防线反而没人管 理解公开是设计使然,安全预算投给规则与认证配置
规则裸奔 数据被爬、被灌垃圾数据,费用与口碑双输 默认拒绝、按需放开、上线前规则评审
私钥进前端或公开仓库 绕过全部规则的管理员权限落入他人之手 私钥只进环境变量、最小权限、泄露立即轮换
读规则过宽被导库 数据被分页爬走 读边界逐条评审,定期规则审计

安全规则的门道远不止这些,但这四类事故覆盖了我见过的绝大多数翻车现场。把它们变成团队的肌肉记忆,你在 Firebase 上就已经比大多数人安全了。