防刷能力取决于后端生成并绑定会话的缺口坐标与前端仅上报归一化偏移,而非滑块样式;前端自算缺口位置易被逆向或绕过,必须由后端返回blockx并校验useroffset像素误差≤5px、token时效性及请求频控。

直接说结论:防刷能力不取决于滑块样式有多炫,而取决于「缺口坐标是否由后端生成并绑定会话」+「前端只上报归一化偏移」。自定义风格可以自由发挥,但绕过这两点,再好看的滑块也是纸老虎。
为什么不能前端自己算缺口位置
常见错误是让前端用 Math.random() 生成缺口 X 坐标,然后画图、校验。这会导致:攻击者直接读取 JS 源码,复现随机逻辑,伪造 userOffset;或干脆跳过前端,构造 POST 请求直连后端接口。
真正安全的做法是:
- 每次验证请求,后端返回三样东西:
bgImage(背景图 base64 或 URL)、sliderImage(缺口图)、blockX(真实缺口横坐标,仅用于后端比对) -
blockX不传给前端渲染用,只存服务端 session 或 Redis,有效期 2 分钟 - 前端渲染时,把
sliderImage固定画在blockY(垂直位置)上,水平位置留空——用户拖动后才决定它停在哪
如何用 movable-area 实现轻量自定义滑块(避开 canvas 兼容坑)
很多团队卡在 canvas 跨域、iOS 裁剪失效、安卓 drawImage 异步失败上。其实 H5 + 小程序场景下,movable-area 更稳,且支持 CSS 自定义:
- 用
<movable-area direction="horizontal" :width="trackWidth"></movable-area>限定轨道宽度,避免拖出界 -
<movable-view></movable-view>里放自定义 icon 或 SVG,通过@change拿到实时e.detail.x,不是clientX - 松手时(
@touchend),计算归一化值:const ratio = Math.min(1, Math.max(0, e.detail.x / trackWidth)) - 提交给后端的不是像素,而是
{ token: 'xxx', userOffset: ratio }—— 这样适配不同屏幕,也防缩放干扰
注意:movable-area 在 App 端需开启 out-of-bounds="true",否则 iOS 上拖动会卡死;H5 端则建议 fallback 到 touchstart/touchmove 手动实现。
防刷必须加的三个服务端动作
前端做得再好,没后端配合就是裸奔。这三个检查缺一不可:
- 验证请求里的
token是否存在且未过期(Redis key TTL ≤ 120s) -
userOffset对应的像素位置(ratio * 图片原始宽度)与服务端存的blockX绝对误差 ≤ 5px(别设 0,人操作总有抖动) - 同一
token的验证请求 1 分钟内只允许成功 1 次,失败超 3 次则冻结该 token 并记录 UA/IP
特别提醒:不要在前端做“滑动距离太短就报错”这类逻辑。攻击者可直接 patch 掉校验函数,或模拟长按后瞬间拖到底——所有容差、频控、冻结都必须落在服务端。
最易被忽略的点:背景图和缺口图必须同源、同尺寸、未经前端缩放处理。哪怕只是 CSS width: 100%,也会让像素比失真,导致后端按原始宽高算的 blockX 对不上。真机调试时,用 uni.getImageInfo 拿到实际加载尺寸再校准。










