HTML5 jQuery游戏分数提交加密及PHP来源验证方案咨询
嘿,做前端游戏防作弊确实得前后端配合着来,光靠某一端肯定扛不住各种骚操作。结合你用PHP+jQuery的场景,给你几个实用的方案,从易到难都有:
方案一:CSRF令牌+Referer验证(基础防护)
这个方案主要解决“非指定页面/域名提交请求”的问题,同时防止跨站请求伪造:
在游戏页面生成CSRF令牌
在你的PHP游戏页面里,启动Session并生成随机令牌,同时输出到页面的隐藏字段中:<?php session_start(); // 生成随机CSRF令牌 if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } ?> <!-- 把令牌藏在页面里,供JS调用 --> <input type="hidden" id="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">提交请求时带上令牌
修改你的jQuery代码,提交分数时同时发送CSRF令牌:if (player.lives === 0) { $.post("submitscore.php", { 'score': player.score, 'csrf_token': $('#csrf_token').val() }, function(data){ }); }后端验证请求合法性
在submitscore.php里先验证令牌,再可选验证请求来源:<?php session_start(); // 核心:验证CSRF令牌 if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { http_response_code(403); exit("Invalid request"); } // 辅助:验证请求来源(注意Referer可能被浏览器禁用,仅作补充) $allowed_domains = ['your-game-domain.com']; // 替换成你的域名 if (isset($_SERVER['HTTP_REFERER'])) { $referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); if (!in_array($referer_host, $allowed_domains)) { http_response_code(403); exit("Unauthorized source"); } } // 后续分数入库逻辑... ?>
注意:Referer字段不是100%可靠,有些浏览器会禁用或允许用户修改,所以只能作为辅助验证,核心还是CSRF令牌。
方案二:分数合理性校验+一次性Nonce(低成本高效防作弊)
很多作弊者会直接提交离谱的高分,这个方案能从根源上挡住这类操作,同时防止重复提交:
生成一次性Nonce
在游戏页面加载时,生成一个只能用一次的随机数,存入Session并传给前端:<?php session_start(); $_SESSION['submit_nonce'] = bin2hex(random_bytes(16)); ?> <input type="hidden" id="submit_nonce" value="<?php echo $_SESSION['submit_nonce']; ?>">提交时带上Nonce
扩展jQuery提交逻辑,加入Nonce:if (player.lives === 0) { $.post("submitscore.php", { 'score': player.score, 'csrf_token': $('#csrf_token').val(), 'nonce': $('#submit_nonce').val() }, function(data){ }); }后端验证分数与Nonce
在submitscore.php里先验证Nonce,再校验分数是否在合理范围内:<?php session_start(); // 先验证CSRF令牌(延续方案一的逻辑) if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { http_response_code(403); exit("Invalid request"); } // 验证Nonce(防止重复提交) if (!isset($_POST['nonce']) || $_POST['nonce'] !== $_SESSION['submit_nonce']) { http_response_code(403); exit("Invalid or reused request"); } // 验证分数合理性(根据你的游戏规则调整最大值) $max_possible_score = 5000; // 比如:每关最多得1000分,共5关 $submitted_score = (int)$_POST['score']; if ($submitted_score < 0 || $submitted_score > $max_possible_score) { http_response_code(400); exit("Invalid score value"); } // 验证通过后销毁Nonce,防止重复使用 unset($_SESSION['submit_nonce']); // 后续分数入库逻辑... ?>
方案三:游戏行为校验(进阶防篡改)
如果想要更严格的防护,可以在前端记录玩家的关键游戏行为,后端验证行为数据与分数是否匹配:
前端记录游戏行为
在游戏过程中记录关键数据(比如消灭敌人数量、关卡进度):// 初始化游戏统计数据 var gameStats = { enemiesKilled: 0, levelsCompleted: 0 }; // 每次消灭敌人时更新统计 function onEnemyKilled() { gameStats.enemiesKilled++; } // 完成关卡时更新统计 function onLevelComplete() { gameStats.levelsCompleted++; }提交时带上行为数据
提交分数时同时发送统计数据:if (player.lives === 0) { $.post("submitscore.php", { 'score': player.score, 'csrf_token': $('#csrf_token').val(), 'nonce': $('#submit_nonce').val(), 'enemies_killed': gameStats.enemiesKilled, 'levels_completed': gameStats.levelsCompleted }, function(data){ }); }后端验证行为与分数匹配
根据你的游戏规则,用行为数据反推合理分数,和提交的分数对比:<?php // 假设:每杀一个敌人得10分,每过一关奖励500分 $calculated_score = ($_POST['enemies_killed'] * 10) + ($_POST['levels_completed'] * 500); if ($calculated_score !== (int)$_POST['score']) { http_response_code(400); exit("Score does not match game stats"); } // 后续逻辑... ?>
总结推荐
最推荐你先用方案一+方案二的组合,成本低、效果好,基本能覆盖大部分常见作弊场景。如果之后遇到更高级的作弊手段,再考虑加上方案三的行为校验。
内容的提问来源于stack exchange,提问作者user1022585

