Firebase Auth规则合规:客户端写入Firestore权限失效及安全实现咨询
解决方案
1. 先修复安全规则的语法错误
你提供的安全规则缺少闭合大括号,这会直接导致规则无法正常生效。另外,为了进一步提升安全性,我们需要限制写入操作只能是递增计数,防止用户篡改字段或设置任意数值:
service cloud.firestore { match /databases/{database}/documents { match /actions/{uid} { // 仅允许认证用户操作自己的文档 allow read, write: if request.auth.uid == uid; // 额外限制写入只能是递增指定动作的计数 allow update: if request.resource.data.keys().size() == 1 && request.resource.data[request.resource.data.keys().first()] is int && request.resource.data[request.resource.data.keys().first()] == resource.data.get(request.resource.data.keys().first(), 0) + 1; } } }
2. 修正客户端代码的核心问题
你的代码存在两个关键隐患:
- 依赖外部传入的
user参数,恶意用户可伪造该参数传入任意UID - 写入字段固定为
action,若action是动作类型(比如"click""scroll"),无法区分不同动作的计数
修正后的代码直接从Firebase Auth获取当前登录用户的UID,彻底避免伪造风险:
import { doc, updateDoc, increment } from "firebase/firestore"; import { getAuth } from "firebase/auth"; export const updateUserWithAction = async (action) => { const auth = getAuth(); const currentUser = auth.currentUser; // 校验用户登录状态 if (!currentUser) { throw new Error("用户未登录,无法记录操作"); } const userDocRef = doc(db, 'actions', currentUser.uid); // 用动态字段名记录对应动作的计数 await updateDoc(userDocRef, { [action]: increment(1) }); };
3. 关键安全逻辑说明
- Firebase Auth认证状态自动同步:只要客户端完成Firebase Auth登录,Firestore安全规则中的
request.auth.uid会自动获取当前用户的真实UID,客户端无法篡改该对象——因为它由Firebase后台验证生成。 - 杜绝客户端传入用户信息:直接使用
getAuth().currentUser获取用户数据,彻底避免恶意用户伪造UID的可能。 - 限制写入操作类型:安全规则中额外校验写入只能是递增操作,防止用户通过修改客户端代码直接设置任意计数(比如把数值改成1000)。
4. 补充:首次操作的文档创建
如果用户第一次执行操作时/actions/{uid}文档不存在,updateDoc会自动创建该文档。若你需要强制文档存在才允许更新,可改用setDoc并设置merge: true,效果与updateDoc一致。
内容的提问来源于stack exchange,提问作者Mark C.
相关产品推荐
相关产品推荐

