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

为无认证的简易Firebase实时按钮配置数据库安全规则

Firebase安全规则配置:无认证下的WordPress实时按钮防篡改方案

首先,你的核心需求很明确:不需要用户认证,只允许前端修改特定的Firebase路径(也就是你的server和timerState节点),同时防止其他路径被篡改,还要保证按钮的正常点击逻辑。直接设"write": false肯定不行,因为你的代码需要更新这两个节点来控制按钮显示和计时器状态。

第一步:精准配置Firebase实时数据库安全规则

你需要针对用到的两个特定路径做权限限制,同时开放必要的读取权限(因为前端要读取状态来更新UI)。这里的关键是只允许写入合法的内容类型,既满足业务需求,又防止恶意篡改。

把你的Firebase安全规则改成下面这样:

{
  "rules": {
    ".read": true, // 前端需要读取所有用到的节点,所以开放全局读取
    ".write": false, // 默认禁止所有写入,只给特定路径开权限
    
    "server": {
      // 只允许写入数字类型(对应你代码里的时间戳)
      ".write": "newData.isNumber()"
    },
    
    "timerState": {
      // 只允许写入"on"或"off"这两个字符串
      ".write": "newData.isString() && (newData.val() === 'on' || newData.val() === 'off')"
    }
  }
}

规则说明:

  • .read: true:你的前端需要读取server的时间戳和timerState的状态来更新计时器和按钮显示,所以全局开放读取是安全的(毕竟这些数据都是公开的状态)。
  • 默认.write: false:从根源上禁止所有未授权的写入,只有指定路径例外。
  • server节点的写入规则:只接受数字,正好匹配你点击按钮时写入的时间戳now = new Date().getTime(),非法的字符串或其他类型都会被拒绝。
  • timerState节点的写入规则:只接受"on"或"off",完全对应你代码里的timerState.set('on')和timerState.set('off'),防止写入其他恶意内容。

第二步:验证你的代码和规则的兼容性

你的现有代码完全符合上面的规则要求:

  • 点击按钮时,你只更新server(写入时间戳数字)和timerState(写入"on")
  • 计时器结束时,你更新server为0(数字)和timerState为"off"

把规则部署后,你的按钮逻辑会正常工作,同时:

  • 任何人都不能修改Firebase里的其他路径(如果有的话)
  • 也不能给server写入非数字内容,或者给timerState写入除了on/off之外的字符串

额外的安全小提示

如果担心有人恶意频繁点击按钮刷写入请求,可以给写入规则加个速率限制,比如限制每个IP每分钟最多写入5次:

"server": {
  ".write": "newData.isNumber() && request.auth == null && request.rateLimit(5, 60000)"
},
"timerState": {
  ".write": "newData.isString() && (newData.val() === 'on' || newData.val() === 'off') && request.auth == null && request.rateLimit(5, 60000)"
}

这里的request.auth == null明确限制无认证的用户(也就是你的场景),rateLimit(5, 60000)表示60秒内最多5次写入请求。

你的完整代码(整理后)

var database = firebase.database(); //firebase queue

//**************
///timer fb
let timestamp;
let now = new Date().getTime();
let endTimeRef = firebase.database().ref("server");
let endTime;
let minutes;
let secondsDisplay;
let distance = endTime - now;
let buttonDisplay = document.getElementById("queue");
let timerDisplay = document.getElementById("timer_fb");
let message = document.getElementById("timer_div");

function displayTimer() {
  minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  secondsDisplay = Math.floor((distance % (1000 * 60)) / 1000);
  let s;
  if (minutes >= 1 || secondsDisplay >= 1) {
    if (minutes >= 1 && secondsDisplay >= 10) {
      s = "Time Until Next Person: " + minutes + ":" + secondsDisplay;
    } else if (minutes >= 1) {
      s = "Time Until Next Person: " + minutes + ":0" + secondsDisplay;
    } else {
      s = "Time Until Next Person: " + secondsDisplay + "s";
    }
  } else {
    s = "";
  }
  document.getElementById("timer_fb").innerHTML = s;
}

function setTimer() {
  let interval = setInterval(function() {
    now = new Date().getTime();
    distance = endTime - now;
    //update timer display
    displayTimer();
    if (distance <= 0) {
      buttonDisplay.style.display = "block";
      timer_div.style.display = "block";
      document.getElementById("timer_div").innerHTML = "This session is open!";
      clearInterval(interval);
      timerState.set('off');
      endTimeRef.set(0);
    }
  }, 1000);
}

//state machine
let timerState = firebase.database().ref("timerState");
let timer;
timerState.on("value", function(snapshot) {
  timer = snapshot.val();
  if(timer == "on"){
    buttonDisplay.style.display = "none";
    message.style.display = "none";
    endTimeRef.once("value", function(snap) {
      let endStamp = snap.val();
      console.log("stored button snap value check: ", snap.val());
      now = new Date().getTime();
      endTime = endStamp + 100000;
      distance = endTime - now;
      //show display right after button is pressed
      displayTimer();
      setTimer();
    });
  }
});

//********
//*****on click handler
document.getElementById("queue").onclick = function() {
  //hide button
  buttonDisplay.style.display = "none";
  message.style.display = "none";
  //set time button comes back
  now = new Date().getTime();
  endTime = now + 100000;
  endTimeRef.set(now);
  //firebase state machine
  timerState.set('on');
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:32:56