验证码图片生成必须用第三方库(如github.com/mojocn/base64captcha),go标准库image包仅支持编码不支持绘图;需复用driver、绑定会话/ip校验、设有效期并立即删除、禁用debug及定制字体。

验证码图片生成要用第三方库,标准库不支持绘图
Go 标准库没有图像绘制能力,image 包只负责数据结构和编码(如 png.Encode),不提供画线、写字、加噪点等操作。必须引入外部绘图库,最常用的是 github.com/golang/freetype + image 组合,但更轻量且专为验证码设计的是 github.com/mojocn/base64Captcha —— 它内置字体、噪声、干扰线,且直接返回 base64 或字节流,省去 HTTP 响应头手动设置的麻烦。
实操建议:
- 用
go get github.com/mojocn/base64Captcha安装,别自己手写绘图逻辑,易出兼容性问题(比如中文字体路径在 Windows/Linux 下不同) - 生成时务必调用
cptr := base64Captcha.NewDriverDigit(...)而非NewDriverString,后者默认含字母,容易被 OCR 识别;纯数字更适合作为入门验证码 - 生成后必须把 captcha ID 和答案存到服务端(如内存 map 或 Redis),不能只靠前端传回的 base64 图片反解——base64 是图片内容,不包含原始文本
验证码 ID 必须通过 Cookie 或 Header 传递,不能依赖 URL 参数
用户请求验证码图片时,Gin 路由(如 GET /captcha)会生成一对 id 和 answer,并把 id 返回给前端。如果把这个 id 放在 URL 里(如 /captcha?id=abc123),下次校验时再从 URL 取,就存在严重安全隐患:URL 可能被代理、CDN、浏览器历史记录泄露,且无法绑定用户会话。
实操建议:
- 生成成功后,用
c.SetCookie("captcha_id", id, 300, "/", "", false, true)写入 HttpOnly Cookie(第三个参数是秒,5 分钟足够) - 校验接口(如
POST /login)直接从c.Cookie("captcha_id")读取,再查存储中的答案;不要让前端在 body 或 query 里重复传id - 若前后端分离且跨域,需确保 Gin 启用 CORS 并设置
AllowCredentials: true,否则浏览器不会发送 Cookie
校验失败要清空服务端记录,防止重放攻击
用户提交表单时,后端用收到的验证码字符串与服务端存储的答案比对。一旦比对完成(无论成功或失败),该 id 对应的记录就必须删除。否则攻击者可截获一次有效的 id/answer 组合,反复提交。
实操建议:
- 用
store.Get(id)获取答案后,立刻调用store.Delete(id)(base64Captcha的Store接口支持) - 不要用 “校验失败才删” 的逻辑——成功后不删,等于留后门;统一在获取后立即删,靠业务逻辑判断是否允许登录
- 如果用内存 map 实现 store,注意并发安全:
sync.Map比普通map+mutex更适合高频读写场景
Gin 中集成时,图片响应类型必须设为 image/png
直接用 c.Data(200, "image/png", bytes) 返回图片字节流,否则浏览器可能下载文件或显示乱码。常见错误是误用 c.String() 或 c.JSON() 包裹 base64 字符串——那只是文本,不是图片资源。
实操建议:
- 生成器返回的是
*base64Captcha.Captcha,其WriteTo(w io.Writer)方法可直接写入c.Writer,比先转[]byte再Data更省内存 - 若用 base64 返回(如用于前端直接
src="data:image/png;base64,..."),需调用cap.WriteEncoding(),并设置响应头c.Header("Content-Type", "application/json") - 测试时用 curl 验证:
curl -I http://localhost:8080/captcha看响应头是否有Content-Type: image/png
真正麻烦的不是生成图片,而是 ID 生命周期管理:生成、透传、校验、销毁,四个环节缺一不可。最容易被忽略的是销毁时机——很多人只在验证成功后删,却忘了失败也得删。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











