HTML5小游戏防作弊核心是提高篡改成本而非杜绝篡改:通过动态键名、内存盐值签名校验、软降级策略及异常捕获,可拦截80%手动修改,且兼顾兼容性与用户体验。

HTML5 小游戏在浏览器端运行,localStorage、sessionStorage 和前端逻辑完全暴露,所谓“防作弊”不是阻止所有篡改,而是提高篡改成本、快速识别异常、让简单修改(比如直接改 score = 999999)立即失效。
为什么 localStorage.setItem('score', '999999') 一试就崩?
因为多数防作弊方案根本没校验——但只要加一层基础校验,就能拦住 80% 的手动修改。关键不在加密多强,而在“校验点是否覆盖关键状态变更”。
- 每次写入
localStorage前,同步生成一个轻量签名,比如:localStorage.setItem('score', score + '|' + md5(score + salt)) - 读取时拆分验证:
const [val, sig] = (localStorage.getItem('score') || '').split('|'); if (sig !== md5(val + salt)) { resetGame(); } - 注意:不要用全局固定
salt,每次页面加载生成一次随机sessionSalt并存入内存(非 storage),否则 salt 被读出就白干 - MD5 不安全?这里不防碰撞,只防明文篡改;用
crypto.subtle.digest反而因兼容性掉坑,md5库几 KB 换来 Chrome/Firefox/Edge 全支持更实际
随机干扰 score 变量名 + 动态存储路径怎么写?
静态键名(如 'score')是作弊者第一眼盯上的目标。把存储路径和变量引用变成运行时拼接,能有效干扰自动化脚本扫描。
- 避免:
localStorage.setItem('score', s); - 改成:
const key = ['sc', 'or', 'e'].join(''); localStorage.setItem(key + Date.now().toString(36).slice(-3), s); - 更进一步:用 Canvas 像素读取、AudioContext 时间戳、甚至
performance.now()的低 3 位做路径扰动因子,让每次存储 key 都不同且不可预测 - 但必须配套清理机制——比如只保留最近 3 个 key,旧 key 用
localStorage.removeItem()主动删,否则 storage 溢出
本地校验失败后该硬重置还是软降级?
校验失败不等于用户作弊,可能是 storage 损坏、跨设备同步冲突、甚至扩展程序误写。粗暴 resetGame() 会激怒真实玩家。
立即学习“前端免费学习笔记(深入)”;
- 优先软处理:
localStorage.removeItem('score'); showToast('记录异常,已恢复默认进度'); - 仅当连续 3 次校验失败(用内存计数器,不依赖 storage)才触发硬重置
- 把校验日志打到
console.warn而非console.error,方便自己调试时区分真异常和用户误操作 - 别忘了:iOS Safari 的 Private Mode 下
localStorage会直接抛QuotaExceededError,需try/catch包裹所有 storage 操作
真正难防的是 hook localStorage.setItem 后拦截并重写校验逻辑——但这已超出“简单作弊”范畴。你做的每层干扰,都在把攻击者从控制台一行命令,推到需要写完整 JS 注入脚本的地步。够用就好,别为防极客搭火箭。











