基于AJAX+PHP的游戏防AJAX POST作弊方案咨询
嘿,我完全懂你这种头疼的感觉——前端请求太容易被篡改了,毕竟浏览器控制台、抓包工具都是玩家随手就能用的。你的核心问题本质是前端不可信,所有关键逻辑和状态绝对不能只依赖前端传过来的数据,得把控制权牢牢握在后端手里。下面给你几个实用的解决方案,结合你的代码场景来拆解:
1. 用Session固定游戏难度,拒绝中途修改
你现在的PHP代码有个明显的逻辑错误:你是先根据前端传的参数赋值$difficulty,再把它存进Session,这等于每次POST请求都会覆盖Session里的难度!正确的做法是:只有游戏初始化阶段,才接受前端的难度选择;一旦游戏开始,就只认Session里存储的难度,完全忽略前端传的难度参数。
修正后的PHP代码示例:
session_start(); // 务必先启动Session,这步很容易忘! if (isset($_POST['clicked'])) { // 只有当Session里还没设置难度(游戏未开始)时,才处理前端的难度选择 if (!isset($_SESSION['difficulty'])) { switch($_POST['clicked']) { case 'easy': $_SESSION['difficulty'] = 1; break; case 'medium': $_SESSION['difficulty'] = 2; break; case 'hard': $_SESSION['difficulty'] = 3; break; default: // 非法请求,默认设为简单难度或直接拒绝 $_SESSION['difficulty'] = 1; } } // 不管前端传什么,后续所有逻辑都用Session里的固定难度 $difficulty = $_SESSION['difficulty']; echo $difficulty; }
这样玩家中途用控制台改POST参数传hard也没用,因为Session里的难度已经固定了——Session存在服务器端,只要你配置好Session安全(比如开启HTTPS、设置HttpOnly和Secure属性),玩家根本没法篡改。
2. 所有奖励发放逻辑必须由后端判断
绝对不能让前端告诉后端“我要什么奖励”,比如玩家通关时,前端只能传「通关的核心数据」(比如完成关卡数、耗时、关键操作记录),后端先验证这些数据是否符合当前Session难度的规则,再决定发什么奖励。
举个例子:如果简单难度要求完成10个关卡,后端收到通关请求时,先查Session里的难度是1,再核对玩家的游戏进度是否真的完成了10个关卡,确认无误后才发放简单难度的奖励——哪怕前端喊破喉咙要困难难度的奖励也没用。
3. 给请求加签名,防篡改
如果确实需要前端传一些数据,可以给请求加个签名,让后端能识别请求是否被篡改:
- 玩家进入游戏时,后端生成一个唯一的密钥(存在Session里,绝对不能传给前端);
- 前端发送请求时,把要传的参数(比如
clicked)和后端给的公开标识(比如Session ID)一起做哈希运算(比如SHA256),得到签名signature; - 前端POST的数据变成
{clicked: "easy", signature: "xxxxxx"}; - 后端收到请求后,用Session里的密钥和传过来的
clicked参数重新计算哈希,对比和前端传的signature是否一致——不一致就直接拒绝请求。
4. 限制请求的时机和频率
- 难度选择只能在游戏开始前进行:在Session里加个
game_started标志,玩家开始游戏后把它设为true,之后收到任何修改难度的请求直接返回错误; - 对通关、领奖励这类关键请求做频率限制,比如1分钟内只能请求1次,防止玩家刷奖励。
5. 验证操作合理性
比如简单难度的通关时间不可能低于10秒,如果玩家传过来的通关时间是2秒,后端直接判定为作弊,拒绝发放奖励。这种合理性检查能挡住很多低级作弊行为。
最后再强调一遍核心原则:永远不要信任前端传过来的任何数据,前端只负责展示和收集用户输入,所有关键的状态、逻辑、奖励发放,必须由后端控制和验证。
内容的提问来源于stack exchange,提问作者Dave

