Go可实现无依赖滑块验证码,关键在动态生成带随机缺口的背景与滑块图、Redis绑定时效性校验、HMAC签名防篡改、±5像素容错及IP绑定,并辅以鼠标行为特征分析提升安全性。

Go 语言本身不内置滑块验证码逻辑,但用 image、crypto/rand 和 HTTP 处理就能在几小时内搭出一个轻量、可控、无第三方依赖的滑块服务——关键不是“能不能做”,而是“怎么避免被绕过”和“怎么不让前端对不上后端校验”。
生成带缺口的拼图背景图与滑块图
滑块验证码的核心是两张图:一张完整背景图(含目标区域),一张小滑块图(从背景图上抠出来的正确位置区块)。不能直接用固定图片,必须每次请求动态生成,且缺口位置要随机、不可预测。
-
image.NewRGBA创建画布,用draw.Draw填充噪点或简单纹理(纯色+高斯模糊也行,重点是让 OCR 和 CV 难以定位边缘) - 用
rand.Intn生成缺口横坐标x(避开边缘,比如限制在80–240像素范围),纵坐标固定居中 - 用
subImage从背景图裁出40×40滑块图(尺寸需和前端 CSS 对齐),同时在背景图上用同色块“盖住”缺口,制造“缺失感” - 两张图都转成
png.Encode输出,响应头设为Content-Type: image/png
注意:别用 time.Now().UnixNano() 当 seed——并发下容易重复;改用 rand.New(rand.NewSource(time.Now().UnixNano() ^ int64(os.Getpid()))) 或直接用 crypto/rand 生成字节再转 int。
后端校验时如何安全比对偏移量
前端拖动后上报一个像素值(如 {x: 152}),但这个值可被篡改。不能只比对是否等于服务端生成的 x,必须加入时效性、绑定性和扰动校验。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 把真实
x存进 Redis,key 为captcha:{uuid},过期时间设为 120 秒,value 是 JSON:{"x":152,"ts":171xxxxxx,"salt":"a2f9..."} - 校验接口收到
x后,先查 Redis,不存在或超时直接拒;再检查ts是否距当前超过 30 秒(防重放) - 计算
hmac-sha256(x + salt + secret_key)作为签名,要求前端也传该签名(由 JS 在本地算好),服务端复现比对 - 允许 ±5 像素误差(防四舍五入/缩放导致的前端取值偏差),但误差值不能硬编码在 JS 里,应由后端下发到前端配置中
前端行为特征辅助判断(非强制但强烈建议)
纯图像校验已不够用。攻击者用 Puppeteer 可以自动识别缺口并拖动。加一层轻量行为分析能筛掉 80% 以上的自动化流量。
- 记录用户鼠标按下(
mousedown)、移动(mousemove)、释放(mouseup)的时间戳和坐标序列,截取前 20 点,压缩成 base64 后随校验请求发出 - 服务端不解析轨迹细节,只做基础判断:是否
mousedown → mousemove → mouseup顺序完整;总耗时是否 30s(挂机);起始点是否在滑块区域内 - 这些字段走
X-Captcha-Traceheader 传,不放 body,避免被表单工具自动带上
不需要训练模型,规则够用。真要对抗高级爬虫,再引入 WebAssembly 版本的轨迹混淆库也不迟。
常见错误:token 未绑定 session 或来源校验缺失
很多实现把 captcha_id 放在 URL 或 localStorage 里反复用,导致一个 token 被多个 IP 复用,或被脚本批量刷接口。
- 生成图片时,必须把
captcha_id和当前请求的RemoteAddr(或更稳的X-Forwarded-For哈希)存入 Redis,校验时比对 IP 前缀(如 /24)是否一致 - 禁止在响应中返回任何可预测的 ID(比如自增整数),一律用
uuid.NewString()或crypto/rand生成 16 字节随机串 - 如果走反向代理(Nginx),确保
X-Real-IP正确透传,否则RemoteAddr会变成127.0.0.1
最常被忽略的是:前端拿到图片后没清空旧 captcha_id,导致用户刷新页面仍用老 ID 请求校验,而后端已删 Redis key——结果永远返回“验证码已过期”。

















