如何限制用户仅能向Firestore的scores集合提交一次通关用时文档
游戏通关分数Firestore提交的安全落地方案
你当前遇到的问题核心是纯前端直连Firestore的架构下,客户端代码完全可控,仅靠前端逻辑的限制对掌握控制台调试能力的用户完全无效,需要从权限边界、提交校验、服务端兜底三个层面搭建防篡改机制,具体可落地的步骤如下:
一、从规则层堵“无限提交”的口子
这一步不需要额外开发后端,只靠Firestore自身的安全规则就能实现单用户仅可提交一次分数的约束:
- 先给所有进入游戏的用户绑定稳定的唯一身份,优先用Firebase匿名登录,不需要用户注册就能生成全局唯一的用户uid,避免无身份用户反复刷提交
- 放弃你当前用随机ID新增文档的写法(也就是
add()方法),改成用用户uid作为scores集合的文档ID,从数据结构上保证一个用户只能对应一个分数文档 - 配置scores集合的写入规则:仅允许已登录用户在对应uid的文档不存在时执行创建操作,一旦文档已存在,后续所有写入请求直接拒绝。这层规则是在Firestore服务端执行的判断,完全不需要信任前端代码,用户就算在前端乱调SDK接口,只要不符合规则就会被直接拦截。
二、从机制上堵“提交任意虚假用时”的漏洞
光限制提交次数还不够,用户依然可以在提交时手动修改time字段,提交远低于真实通关时间的作弊值,这部分可以根据项目规模选择适配的校验方案:
- 小型项目/个人项目轻量方案:收回前端对scores集合的直接写入权限,仅保留调用云函数的权限。游戏启动时由云函数记录用户的进入时间戳,用户每完成一个关卡节点就上报一次进度,当云函数确认用户完成全部关卡流程、累计时间差符合游戏时长逻辑时,直接由云函数用管理员权限写入对应uid的分数文档。这种模式下前端根本没有直接写scores集合的接口权限,就算用户复制粘贴原来的调用代码,也会因为权限不足写入失败。
- 更轻量的过渡方案:游戏启动时由Firestore自动下发一个一次性的随机校验凭证,用户通关提交分数时必须携带这个凭证提交,规则层校验凭证有效性、是否被使用过,校验通过后立刻作废凭证,避免用户复用凭证反复提交虚假分数。
注意:不要尝试靠前端控制“提交按钮点击一次后置灰”来防刷,这类逻辑全部运行在用户本地,通过浏览器控制台几行代码就能轻易绕过,所有安全校验逻辑必须放在服务端(Firestore规则/Cloud Functions)执行。
三、你现有代码的最小改造路径
你现在的示例代码db.collection('score').add({ time: 122, });有两个需要优先调整的硬伤:
- 先把集合名的拼写和你提到的
scores对齐(你代码里写的是单数形式的score),避免集合名不统一导致的规则不生效问题 - 把随机新增的
add()改成绑定用户身份的文档写入:db.collection('scores').doc(当前登录用户uid).set({ time: 122, createTime: firebase.firestore.FieldValue.serverTimestamp() }) - 额外补充字段范围校验:在安全规则里判断提交的time值必须在游戏合理的时长区间内(比如最短通关时间不能低于3秒、最长不能超过游戏设计的总时长),拦截明显不合理的虚假提交。
内容的提问来源于stack exchange,提问作者Jgecc
相关产品推荐
相关产品推荐

