不能直接用 DefaultMemStore,因其为内存 map,服务重启即丢失且无法跨实例共享;必须实现 Store 接口并用 Redis 存储,key 为 "captcha:" + id,TTL 设 5–10 分钟,校验后显式 delete;需绑定用户上下文(session 或 IP+UA 哈希),禁用 debug,驱动参数须强化抗 OCR 能力。

别用默认内存存储,也别让前端自由传 captchaId 去校验——否则验证码形同虚设。
为什么不能直接用 base64Captcha.DefaultMemStore
它本质是 map + sync.RWMutex,服务重启即清空,且无法跨实例共享。在多副本部署(如 Kubernetes)下,用户请求落到 A 实例生成的 captchaId,却可能被转发到 B 实例校验,必然失败。
- 必须实现
base64Captcha.Store接口,推荐用 Redis:key 为"captcha:" + id,value 为明文答案,TTL 设为 5–10 分钟(time.Minute * 5) - 若暂无 Redis,可用
github.com/go-redis/redis/v8封装一个轻量RedisStore,注意Get方法里clear=true时要调用Del而非仅Get - 切勿在 handler 里每次 new 一个
base64Captcha.Captcha实例——驱动(DriverString或DriverDigit)含字体加载和绘图上下文,高频 new 会触发内存泄漏
如何绑定验证码到具体用户上下文而非裸 ID
攻击者可遍历 captchaId(比如从 "a1" 到 "z9999")批量重放 POST /verify 请求。关键不是“ID 是否存在”,而是“这个 ID 是否属于当前操作者”。
- 有 session 场景(如登录页):生成后立即执行
session.Set("captcha_id", id);校验前先取session.Get("captcha_id"),与请求中id比对一致才调用store.Verify - 无 session 场景(如开放 API):用
hash := fmt.Sprintf("%x", md5.Sum([]byte(c.ClientIP() + c.GetHeader("User-Agent"))))作 key 前缀,存为"captcha:" + hash + ":" + id,避免 IP 池穿透 - 绝对禁止把
captchaId放 query string 里传给校验接口——它会被 CDN、代理、日志系统明文记录
base64Captcha.DriverString 的抗 OCR 关键参数怎么调
纯数字 4 位太弱,全字母又易输错;倾斜+噪点+干扰线强度不够,OCR 准确率能到 90%+。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 长度固定为 5 或 6,
Source必须混入大小写字母+数字,剔除易混淆字符(如0/O/l/I/1),例如:"23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ" -
NoiseCount: 8(比默认 5 更高),ShowLineOptions: base64Captcha.OptionShowSineLine | base64Captcha.OptionShowSlimeLine(双干扰线) - 开启扭曲:
RotateRange: base64Captcha.Range{Min: -15, Max: 15};背景色用低饱和度蓝灰(&color.RGBA{R: 230, G: 238, B: 255, A: 255}),文字色用深灰(&color.RGBA{R: 51, G: 51, B: 51, A: 255}) - 字体务必指定真实存在的 ttf 文件路径(如
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"),Windows 下注意反斜杠转义或用正斜杠
校验成功后必须立刻清理,且禁用 debug 模式
debug 模式下 base64Captcha 会在日志打印明文答案,上线即成漏洞;而校验通过却不删记录,等于放行无限次重放。
- 校验逻辑结尾必须加
store.Delete(id),哪怕Verify第三个参数设为true,也要再显式删一次——某些自定义 store 实现可能忽略该 flag - 启动 Gin 前确保
gin.SetMode(gin.ReleaseMode),或设置环境变量GIN_MODE=release - 生成接口返回体里不要带答案字段,哪怕注释掉也不行;CI/CD 流水线应扫描代码中是否出现
log.Print.*answer或fmt.Printf.*%s.*answer
最常被跳过的一步:没做请求指纹绑定。很多人只实现了「生成→存 Redis→校验→删」闭环,却忘了校验前少了一次「当前请求是否配得上这个 ID」的判定——这层校验才是防批量攻击的真正门槛。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










