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

如何安全传递JS变量highScore至PHP并防止分数恶意篡改?

可靠的分数防篡改方案

由于前端代码完全暴露,任何前端加密/混淆逻辑都能被破解,核心思路必须是让服务器掌握验证分数的关键信息,而非依赖前端计算。以下是几个可落地的实战方案:

方案一:会话级签名验证(推荐)

  1. 游戏初始化时获取会话密钥
    用户进入游戏页面时,由PHP生成绑定当前$_SESSION的唯一随机密钥,并返回给前端:
// game_init.php
session_start();
// 生成16字节随机密钥,仅存于当前会话
$_SESSION['score_sign_key'] = bin2hex(random_bytes(16));
echo json_encode(['sign_key' => $_SESSION['score_sign_key']]);

前端通过AJAX请求该接口获取密钥,仅存在内存中(不要存localStorage或cookie,避免泄露)。

  1. 前端计算签名并提交
    游戏结束时,用密钥对分数+会话ID做哈希计算,将分数和签名一同传给后端:
// 假设已从game_init.php拿到signKey,会话ID从页面渲染时嵌入
const highScore = 1234;
const sessionId = "<?php echo session_id(); ?>";
// 用原生CryptoAPI或第三方库生成SHA-256哈希
const signature = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(highScore + sessionId + signKey));
const signatureHex = Array.from(new Uint8Array(signature)).map(b => b.toString(16).padStart(2, '0')).join('');

// 用POST提交数据
fetch('writescore.php', {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: `score=${highScore}&signature=${signatureHex}`
});
  1. 后端验证签名有效性
    后端拿到参数后,用会话内存储的密钥重新计算签名,与前端提交的对比:
// writescore.php
session_start();
if (!isset($_SESSION['score_sign_key'], $_POST['score'], $_POST['signature'])) {
  die("非法请求");
}

$score = (int)$_POST['score'];
$sessionId = session_id();
// 重新计算预期签名
$expectedSignature = hash('sha256', $score . $sessionId . $_SESSION['score_sign_key']);

if ($expectedSignature !== $_POST['signature']) {
  die("分数篡改");
}

// 验证通过后写入数据库,同时销毁密钥防止重复提交
unset($_SESSION['score_sign_key']);
// 执行数据库写入逻辑

优势:密钥绑定当前会话且一次性使用,攻击者无法伪造签名(不知道会话内的密钥),安全性极高。

方案二:服务器端计算最终分数

如果游戏有明确的关卡、任务等进度节点,可让服务器全程跟踪进度,最终分数由服务器计算而非前端传递:

  • 前端每完成一个关卡/任务,调用update_progress.php提交进度(如?level=5)
  • 后端记录用户的进度数据、耗时等信息
  • 游戏结束时,后端根据记录的进度自动计算最终分数,无需前端传值

优势:彻底杜绝前端篡改分数的可能,适合规则明确的游戏,但需要改造现有游戏逻辑。

方案三:时间窗口+签名双重验证

若不想大幅修改游戏逻辑,可在现有基础上升级验证机制:

  1. 游戏开始时生成带有效期的token
session_start();
$expire = time() + 600; // 设置10分钟有效期
// 用用户ID、有效期、服务器私密密钥生成token
$token = hash('sha256', $_SESSION['user_id'] . $expire . 'your_server_secret_key');
$_SESSION['score_token'] = [$token, $expire];
echo json_encode(['token' => $token, 'expire' => $expire]);
  1. 前端提交分数时携带token和时间戳
const highScore = 1234;
const currentTime = Math.floor(Date.now()/1000);
fetch('writescore.php', {
  method: 'POST',
  body: `score=${highScore}&token=${token}&time=${currentTime}`
});
  1. 后端多重验证
  • 检查当前时间是否在token有效期内
  • 用用户ID、有效期、服务器密钥重新计算token,与前端提交的对比
  • 限制单用户短时间内的分数提交次数

避坑提醒

  • 绝对不要把验证用的密钥写在前端代码里,哪怕混淆也会被破解
  • 提交分数必须用POST请求,避免参数在URL中泄露
  • 数据库记录用户提交分数的时间、IP等信息,事后可人工排查异常(如突然出现远超正常水平的分数)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:17:49