纯前端HTML+JS实现的滑动拼图验证码不能用于生产环境的身份校验,因其所有逻辑(含targetX/targetY生成、缺口定位、验证判断)均在客户端执行,攻击者可通过开发者工具直接读取变量、hook事件或重放请求绕过验证,且缺少服务端出题、验题与安全随机数生成等核心环节。

纯前端 HTML + JS 实现的滑动拼图验证码,**不能用于生产环境的身份校验**。它看起来能“验证”,但用户只要打开开发者工具、搜索 targetX 和 targetY,就能直接算出正确位置——连重放都不用,更别提绕过。
为什么不能只靠前端生成缺口和拼图
所有资料里出现的 Math.random() 生成缺口坐标、canvas.drawImage() 截取拼图块、用 getBoundingClientRect() 判断拖拽终点——这些逻辑全在浏览器里跑,意味着:
- 真实答案(即缺口横纵坐标)始终暴露在 JS 变量或闭包中
- 攻击者可 hook
onmouseup事件,直接读取当前滑块 left 值并比对 - 没有服务端参与的“验证”只是 UI 反馈,后端根本不知道用户是否真对齐了
你看到的成功提示,只是 if (Math.abs(currentX - targetX) 的结果,和服务器零交互。
如果非要前端先搭个 Demo,关键三步不能少
只是为了快速预览效果或教学演示,可保留前端逻辑,但必须明确边界:它只负责渲染和交互反馈,**不承担安全职责**。实操时注意:
-
targetX和targetY必须在每次初始化时重新生成,不能写死或缓存在全局变量里 - 拼图块的
background-position要严格对应缺口在原图中的偏移,例如缺口在left: 280px; top: 100px,拼图块就要设background-position: -280px -100px - 拖拽结束时,校验阈值建议设为
2~5像素,太松(如10)易误判,太严(如0)影响移动端手指操作
示例片段(仅示意校验逻辑):
document.addEventListener('mouseup', () => {
const slider = document.querySelector('.slider');
const left = parseInt(slider.style.left) || 0;
// 假设目标位置换算为滑块 left 值是 240
if (Math.abs(left - 240) slider.classList.remove('fail'), 800);
}
});
真正上线前,必须补的服务端环节
前端拼图只是“画布”,后端才是“出题人+阅卷人”。缺以下任意一环,就等于没验证码:
- 后端接口(如
/captcha/init)返回:带缺口的背景图 URL、拼图块 URL、以及一个加密的token(关联 session 或 Redis 中存储的真实targetX/targetY) - 前端提交时,把用户拖拽结束的
left值 +token一起发给后端(如/captcha/verify),由服务端比对,而非前端 JS - 后端响应必须是布尔值(
{ success: true }),前端只据此更新 UI,绝不自行判断
最容易被忽略的是:**后端生成图片时,必须用 secrets(Python)或 crypto.getRandomValues()(JS 服务端)代替 Math.random()**。前者不可预测,后者可被 seed 暴力还原——这决定了攻击者是花 1 分钟看源码,还是花 1 小时写脚本批量破解。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











