HTML无法防作弊,因其仅为标记语言;可信校验必须由服务端完成,前端仅负责状态呈现,所有关键逻辑如成就解锁、行为检测等均需服务端验证上下文并拒绝非法请求。

HTML 本身无法实现防作弊,别在 里埋逻辑HTML 是纯标记语言,没有执行能力,所有“成就解锁”“进度校验”“行为检测”如果只靠 HTML 标签或属性(比如 data-achieved、hidden、disabled)来控制,用户开开发者工具一改就失效。这不是漏洞,是设计使然——浏览器渲染层不负责可信计算。
常见错误现象:document.getElementById('achievement-vip').classList.add('unlocked') 被手动触发后,成就图标显示了,但服务器根本不知道;或者用 localStorage.setItem('level', '99') 模拟升级,刷新页面就“继承”,但后端查不到记录。
- 真正可信的判断必须落在服务端:每次成就达成请求,都需携带不可伪造的上下文(如 session token + 行为时间戳 + 客户端签名 hash)
- 前端 HTML 只负责“呈现状态”,不是“决定状态”;
data-verified="false" 这类属性只能用于调试标记,不能作为权限开关
- 把校验逻辑塞进
<script></script> 也不够——JS 可被禁用、绕过、重写,尤其在无 HTTPS 或未启用 Content-Security-Policy 的页面上更危险
用 IntersectionObserver 检测“真实观看”但别信它能防刷
想确认用户是否真的滚动到了成就说明区域?IntersectionObserver 是目前最合理的 DOM 行为检测手段,但它只回答“元素是否出现在视口”,不回答“人是否在看”。自动化脚本、headless 浏览器、甚至鼠标宏都能轻易触发它。
使用场景:配合后端日志做行为分析(例如“85% 用户在触发 achievements-tutorial 观察器后 3 秒内点击下一步”),而不是直接解锁成就。
- 不要用
observer.observe(document.getElementById('achievement-badge')) 后立刻发成就领取请求
- 加最小停留时间阈值:比如
intersectionRatio > 0.7 && entry.time - entry.startTime > 2000
- 避免监听
body 或全屏元素——它们太容易被误触发;优先选具体卡片、按钮、说明块等有语义的
- 注意兼容性:
IntersectionObserver 在 IE 完全不支持,iOS Safari 12.2+ 才支持 threshold 数组,老版本需降级为 scroll + getBoundingClientRect
fetch() 提交成就时必须带服务端可验证的上下文
用户点“领取成就”按钮,前端调 fetch('/api/claim', { method: 'POST', body: JSON.stringify({ id: 'speedrun' }) }) ——这请求本身毫无可信度。攻击者用 curl 或 Postman 照样能发,只要知道接口路径和格式。
关键不是“怎么发”,而是“凭什么信这是合法触发”。服务端必须拒绝任何缺少以下至少两项的请求:
-
X-Request-ID 或类似一次性 token(由上一步交互生成,15 分钟内有效)
- 客户端行为指纹字段,如
navigator.hardwareConcurrency + screen.width + performance.now() 的简单哈希(不加密,仅防明显篡改)
- 与当前登录态强绑定的字段,如 JWT 中的
user_id 和 session_id,且服务端要校验该 session 是否仍活跃、是否有对应行为日志
性能影响很小,但漏掉任意一项,就等于把成就系统大门钥匙挂在门把手上。
防异常操作得靠服务端日志聚类,不是前端拦 click
想防连点、脚本刷成就?监听 click 并加 setTimeout 防抖只是障眼法。真实异常行为(比如 1 秒内触发 20 次“观看视频”事件)必须靠服务端聚合分析:同一 user_id + 同一 ip + 相同 user_agent + 时间窗口内高频请求,才可能判定为可疑。
前端能做的只有配合:每次行为上报都带上 timestamp(用 Date.now(),别用服务端返回的时间)、page_url、referrer,并确保这些字段不被轻易伪造(例如通过 service worker 拦截修改)。
- 别在前端做“第 5 次点击就禁用按钮”——用户清 localStorage 就重置了
- 服务端收到行为事件后,先查 Redis 缓存中该用户最近 60 秒的操作次数,超阈值直接拒收并记日志
- 对高风险成就(如“首充奖励”“邀请 10 人”),额外要求二次确认(短信/邮箱验证码),且验证码必须和服务端 session 绑定,不能靠前端传来的手机号直接发
最常被忽略的一点:所有客户端上报的时间戳、坐标、停留时长,都只是参考数据。服务端永远以自己的 clock、IP 地理库、行为序列模型为准——前端只是传感器,不是法官。
HTML 是纯标记语言,没有执行能力,所有“成就解锁”“进度校验”“行为检测”如果只靠 HTML 标签或属性(比如 data-achieved、hidden、disabled)来控制,用户开开发者工具一改就失效。这不是漏洞,是设计使然——浏览器渲染层不负责可信计算。
常见错误现象:document.getElementById('achievement-vip').classList.add('unlocked') 被手动触发后,成就图标显示了,但服务器根本不知道;或者用 localStorage.setItem('level', '99') 模拟升级,刷新页面就“继承”,但后端查不到记录。
- 真正可信的判断必须落在服务端:每次成就达成请求,都需携带不可伪造的上下文(如 session token + 行为时间戳 + 客户端签名 hash)
- 前端 HTML 只负责“呈现状态”,不是“决定状态”;
data-verified="false"这类属性只能用于调试标记,不能作为权限开关 - 把校验逻辑塞进
<script></script>也不够——JS 可被禁用、绕过、重写,尤其在无 HTTPS 或未启用Content-Security-Policy的页面上更危险
用 IntersectionObserver 检测“真实观看”但别信它能防刷
想确认用户是否真的滚动到了成就说明区域?IntersectionObserver 是目前最合理的 DOM 行为检测手段,但它只回答“元素是否出现在视口”,不回答“人是否在看”。自动化脚本、headless 浏览器、甚至鼠标宏都能轻易触发它。
使用场景:配合后端日志做行为分析(例如“85% 用户在触发 achievements-tutorial 观察器后 3 秒内点击下一步”),而不是直接解锁成就。
- 不要用
observer.observe(document.getElementById('achievement-badge'))后立刻发成就领取请求 - 加最小停留时间阈值:比如
intersectionRatio > 0.7 && entry.time - entry.startTime > 2000 - 避免监听
body或全屏元素——它们太容易被误触发;优先选具体卡片、按钮、说明块等有语义的 - 注意兼容性:
IntersectionObserver在 IE 完全不支持,iOS Safari 12.2+ 才支持threshold数组,老版本需降级为 scroll + getBoundingClientRect
fetch() 提交成就时必须带服务端可验证的上下文
用户点“领取成就”按钮,前端调 fetch('/api/claim', { method: 'POST', body: JSON.stringify({ id: 'speedrun' }) }) ——这请求本身毫无可信度。攻击者用 curl 或 Postman 照样能发,只要知道接口路径和格式。
关键不是“怎么发”,而是“凭什么信这是合法触发”。服务端必须拒绝任何缺少以下至少两项的请求:
-
X-Request-ID或类似一次性 token(由上一步交互生成,15 分钟内有效) - 客户端行为指纹字段,如
navigator.hardwareConcurrency+screen.width+performance.now()的简单哈希(不加密,仅防明显篡改) - 与当前登录态强绑定的字段,如 JWT 中的
user_id和session_id,且服务端要校验该 session 是否仍活跃、是否有对应行为日志
性能影响很小,但漏掉任意一项,就等于把成就系统大门钥匙挂在门把手上。
防异常操作得靠服务端日志聚类,不是前端拦 click
想防连点、脚本刷成就?监听 click 并加 setTimeout 防抖只是障眼法。真实异常行为(比如 1 秒内触发 20 次“观看视频”事件)必须靠服务端聚合分析:同一 user_id + 同一 ip + 相同 user_agent + 时间窗口内高频请求,才可能判定为可疑。
前端能做的只有配合:每次行为上报都带上 timestamp(用 Date.now(),别用服务端返回的时间)、page_url、referrer,并确保这些字段不被轻易伪造(例如通过 service worker 拦截修改)。
- 别在前端做“第 5 次点击就禁用按钮”——用户清 localStorage 就重置了
- 服务端收到行为事件后,先查 Redis 缓存中该用户最近 60 秒的操作次数,超阈值直接拒收并记日志
- 对高风险成就(如“首充奖励”“邀请 10 人”),额外要求二次确认(短信/邮箱验证码),且验证码必须和服务端 session 绑定,不能靠前端传来的手机号直接发
最常被忽略的一点:所有客户端上报的时间戳、坐标、停留时长,都只是参考数据。服务端永远以自己的 clock、IP 地理库、行为序列模型为准——前端只是传感器,不是法官。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











