Firebase Storage Rules v2 禁止update仍可覆盖现有文件异常
你遇到的现象既不是Firebase Storage Rules的bug,也不是官方文档对粒度权限的描述有问题,本质是两个测试环节的认知错位:一是规则的路径匹配范围写错了,二是测试代码里的上传逻辑根本没有触发你以为的“覆盖文件”的update操作。
你对v2规则粒度化权限的核心理解是符合官方定义的:
- 当向不存在的目标文件路径发起写请求时,操作类型判定为
create,仅受create规则约束 - 当向已经存在的目标文件路径发起写请求时,操作类型判定为
update,仅受update规则约束 - 删除操作单独受
delete规则约束 - 单文件读操作受
get规则约束,列表查询类操作受list规则约束
如果规则路径正确匹配,这个判定逻辑是完全生效的,不存在规则漏洞。
1. 规则的路径匹配范围理解错误
很多刚接触Storage Rules的开发者都会踩这个坑:Firebase Storage本身没有实体的文件夹概念,所有路径本质上都是具体文件的完整路径,所谓的“文件夹”只是一组文件路径的公共前缀而已。
你现在写的规则match /randomFiles,在系统眼里实际匹配的是路径恰好为randomFiles的单个文件对象,根本覆盖不到这个前缀下的任何子文件。未被任何match规则覆盖的路径,会默认拒绝所有访问请求。
如果你要给randomFiles目录下的所有第一层级子文件配置规则,正确写法是:
match /randomFiles/{fileName} { // 你的权限规则 }
如果要覆盖该目录下任意深度的所有子文件,需要用递归通配符:
match /randomFiles/{allPaths=**} { // 你的权限规则 }
2. 测试代码的上传逻辑没有触发“覆盖文件”的update操作
Flutter端firebase_storage插件有一个非常容易踩坑的行为:当你对一个代表目录前缀的Reference直接调用putFile时,插件会自动提取本地文件的文件名,拼接为完整的文件路径执行上传,不会把文件内容上传到这个目录节点本身(毕竟存储系统里根本不存在目录实体)。
对应你的测试代码:
- 第一次上传时,目标路径会被拼接为
filesDir/someimage.png - 第二次上传时,目标路径会被拼接为
filesDir/otherImage.jpeg
这两个是完全独立的文件对象,不存在“后一次上传覆盖前一次文件”的关系,两次操作都是往不存在的新路径写文件,自然都会通过create权限校验、返回成功。
如果你要真正测试“覆盖已存在文件”的行为,必须两次上传都使用同一个完整文件路径的Reference,比如:
// 固定使用同一个目标文件路径 Reference targetRef = FirebaseStorage.instance.ref("filesDir/test_cover.jpg"); // 第一次上传 await targetRef.putFile(File("lib/someimage.png")); // 第二次往同一个路径上传不同文件,这才是触发update操作的场景 await targetRef.putFile(File("lib/otherImage.jpeg"));
这个时候第二次上传才会被判定为对已存在文件的update操作,如果规则里update权限设为false,请求会被直接拒绝。
你之前的测试还有一个容易忽略的错位:测试代码里的上传路径是filesDir,但你写的规则声明的权限路径是randomFiles,两个路径完全没有交集。正常情况下没有匹配到规则的请求应该被拒绝,如果你实际测试时确实上传成功了,大概率是测试过程中调整过路径让规则匹配上了,但始终没有触发真正的update校验场景。
内容的提问来源于stack exchange,提问作者Eduardo Yamauchi

