You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止用户篡改APK以修改Firestore中用户的Credit余额?

防止客户端篡改Firestore金币余额的解决方案

核心原则:客户端完全不可信,所有涉及余额变更的操作必须在服务端或通过安全规则做严格校验,绝不能让客户端直接控制余额数值。

1. 用Firestore安全规则限制非法写入

不要给客户端直接修改余额字段的权限,只允许符合业务逻辑的增量/减量操作,同时在规则里做校验:

  • 仅允许登录用户修改自己的Credit文档
  • 限制余额只能做合法变更:比如扣除金币时,新余额必须小于等于原余额,且扣除金额为正数;增加金币时(比如奖励),可结合业务字段验证操作合法性(如是否有对应的任务完成记录)
  • 禁止客户端替换整个文档,只能更新指定字段

示例安全规则:

match /users/{userId}/Credit/{creditDocId} {
  // 仅允许登录用户操作自己的余额文档
  allow read: if request.auth != null && request.auth.uid == userId;
  allow write: if request.auth != null && request.auth.uid == userId
    // 仅允许两种操作:扣减或增加余额,且操作参数合法
    && (
      // 扣减逻辑:新余额 = 原余额 - 扣减金额,且扣减金额>0,新余额≥0
      (request.data.deduct is number 
        && request.data.deduct > 0
        && request.resource.data.balance == resource.data.balance - request.data.deduct
        && request.resource.data.balance >= 0)
      ||
      // 增加逻辑:新余额 = 原余额 + 增加金额,且增加金额>0
      (request.data.add is number 
        && request.data.add > 0
        && request.resource.data.balance == resource.data.balance + request.data.add)
    );
}

客户端调用时,只能通过指定的deduct或add参数发起操作,比如用FieldValue.increment()配合规则校验,而不是直接设置balance的值。

2. 将余额变更逻辑完全移到服务端(Cloud Functions)

这是最安全的方案:不让客户端直接触碰Credit文档,所有余额变更请求都通过Cloud Functions处理,所有校验逻辑在服务端完成:

  • 客户端调用云函数,传入操作类型(如购买商品、领取任务奖励)和必要参数(如商品ID、任务ID)
  • 云函数先验证用户身份,再校验操作的合法性(比如从服务端数据库读取商品真实价格,检查用户是否完成任务)
  • 最后通过事务修改Firestore余额,避免并发问题

示例Node.js云函数:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.processCreditChange = functions.https.onCall(async (data, context) => {
  // 验证用户是否登录
  if (!context.auth) {
    throw new functions.https.HttpsError("unauthenticated", "请先登录");
  }
  const userId = context.auth.uid;
  const { operationType, targetId } = data;

  // 根据操作类型做不同校验
  let changeAmount = 0;
  if (operationType === "BUY_PRODUCT") {
    // 从服务端读取商品真实价格,拒绝信任客户端传的价格
    const productDoc = await admin.firestore().collection("products").doc(targetId).get();
    if (!productDoc.exists) {
      throw new functions.https.HttpsError("not-found", "商品不存在");
    }
    changeAmount = -productDoc.data().price; // 扣减为负数
    if (changeAmount >= 0) {
      throw new functions.https.HttpsError("invalid-argument", "商品价格非法");
    }
  } else if (operationType === "CLAIM_REWARD") {
    // 验证用户是否完成该任务
    const taskRecordDoc = await admin.firestore().collection("userTasks").doc(`${userId}_${targetId}`).get();
    if (!taskRecordDoc.exists || !taskRecordDoc.data().completed) {
      throw new functions.https.HttpsError("failed-precondition", "未完成任务,无法领取奖励");
    }
    // 读取奖励金额
    const taskDoc = await admin.firestore().collection("tasks").doc(targetId).get();
    changeAmount = taskDoc.data().reward;
    if (changeAmount <= 0) {
      throw new functions.https.HttpsError("invalid-argument", "奖励金额非法");
    }
    // 标记奖励已领取,避免重复领取
    await taskRecordDoc.ref.update({ rewardClaimed: true });
  } else {
    throw new functions.https.HttpsError("invalid-argument", "不支持的操作类型");
  }

  // 用事务修改余额,防止并发冲突
  const creditDocRef = admin.firestore().collection("users").doc(userId).collection("Credit").doc("userCredit");
  const newBalance = await admin.firestore().runTransaction(async (t) => {
    const creditDoc = await t.get(creditDocRef);
    if (!creditDoc.exists) {
      // 首次使用,初始化余额为0
      t.set(creditDocRef, { balance: 0 + changeAmount });
      return changeAmount;
    }
    const currentBalance = creditDoc.data().balance;
    if (currentBalance + changeAmount < 0) {
      throw new functions.https.HttpsError("failed-precondition", "余额不足");
    }
    t.update(creditDocRef, { balance: currentBalance + changeAmount });
    return currentBalance + changeAmount;
  });

  return { newBalance };
});

3. 额外的安全加固措施

  • 不在客户端存储敏感数据:不要在APK里硬编码商品价格、奖励金额等数值,所有业务数据都从服务端实时获取
  • 启用审计日志:开启Firestore的审计功能,监控所有余额变更操作,发现异常(比如频繁无理由增加余额)及时处理
  • 请求签名校验:客户端发起请求时,带上服务端生成的签名,服务端验证签名合法性后再处理,防止篡改请求参数
  • 定期一致性校验:定时运行云函数,对比用户余额和业务记录(如购买记录、奖励记录),确保余额和操作流水一致

内容的提问来源于stack exchange,提问作者faccio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:24:15