beego原生captcha模块无干扰线、噪点、扭曲及自定义字体,仅用8×16位图硬编码渲染纯色文字+边框,抗ocr能力弱;应替换为base64captcha或dchest/captcha等成熟库,并补全session绑定、redis存储、有效期清理等安全链路。

Beego 自带的 captcha 模块默认不生成干扰线,也不支持扭曲、噪点或自定义字体——它只是用位图字体画出纯色文字+简单边框,抗 OCR 能力弱,直接用于生产环境有风险。
Beego 的 captcha.Captcha 为什么没有干扰线
Beego 的 github.com/astaxie/beego/utils/captcha 是一个轻量封装,底层没调用任何图像绘制库(如 image/draw 或 gg),而是靠内置的 8×16 位图字模硬编码渲染字符。它不生成 PNG 文件流,而是返回 base64 字符串或通过 /captcha/:id.png 路由动态响应,但所有图形元素(包括背景、文字、边框)都是静态绘制逻辑,**没有干扰线、没有噪点、不能旋转、不支持中文或 TTF 字体**。
常见错误现象:VerifyReq 总是返回 false,或者验证码图片看起来“太干净”,一抓一个准。
- 干扰线、扭曲、噪点等增强策略在 Beego 原生 captcha 中完全缺失
-
StdWidth/StdHeight只控制画布尺寸,不影响图形复杂度 - 即使你改了
ChallengeNums或Expiration,也改变不了它“无干扰”的本质
想加干扰线?别修 Beego 的 captcha,换库
强行给 Beego 的 captcha.Captcha 注入干扰线需要重写整个 Draw 流程,成本远高于替换——推荐直接接入更成熟的第三方方案,并与 Beego 路由/模板兼容。
实操建议:
- 用
github.com/mojocn/base64Captcha:输出 base64 字符串,免 HTTP 图片路由,干扰线/噪点/倾斜/字体渲染全内置,只需替换模板中{{create_captcha}}为手动插入<img src="data:image/png;base64,xxx"> - 用
github.com/dchest/captcha:保持 URL 接口风格(如/captcha/:id.png),需额外注册字体(font.Register)才能启用抗锯齿和干扰线;默认已开启干扰线,但必须调用captcha.GenerateCaptcha(id, 5)显式生成,不能依赖 Beego 的自动路由 - 避免
github.com/disintegration/imaging单独绘图:它适合做图像处理,不是验证码专用库,加干扰线要自己循环画线、抖动坐标、叠加噪点,容易漏设Content-Type或 alpha 值导致文字被盖住
Beego 中安全集成第三方验证码的关键动作
换了库不等于安全,Beego 的生命周期和缓存模型容易放大配置失误。
必须做的几件事:
- 禁用默认内存存储:Beego 的
cache.NewMemoryCache()重启即丢,且无法跨实例共享;换成 Redis 或自定义 store,调用captcha.SetCustomStore(...) - 绑定校验上下文:不要只校验
captcha.VerifyString(id, input),必须把id和当前 session / IP + UA 哈希绑定,否则攻击者可遍历id=1到id=1000批量重放 - 设有效期并立即删除:Beego 的
Expiration默认是 10 分钟,但校验成功后务必调用captcha.Delete(id),否则同一验证码可重复使用 - 模板里禁用前端缓存:
<img src="/captcha/%7B%7B.id%7D%7D.png?ts=%7B%7Bnow.Unix%7D%7D">,防止浏览器或 CDN 缓存旧图
Beego 模板里怎么显示带干扰线的验证码
Beego 原生 {{create_captcha}} 是个黑盒函数,它生成的 HTML 已固化结构(含隐藏字段、onclick 刷新逻辑),没法注入干扰线。你得绕过它,手写 HTML + JS 控制。
以 base64Captcha 为例:
func (c *LoginController) Get() {
id, b64s, err := captcha.GenerateCaptcha("", 4)
if err != nil {
c.Abort("500")
return
}
c.Data["CaptchaID"] = id
c.Data["CaptchaImg"] = b64s
c.TplName = "login.html"
}
模板中写:
<input type="text" name="captcha" placeholder="验证码"><input type="hidden" name="captcha_id" value="{{.CaptchaID}}">
@@##@@
JS 刷新逻辑里调后端新接口获取新 id 和 b64s,而不是依赖 Beego 的 /captcha/xxx.png 路由。
注意:base64Captcha 默认 driver 是 DriverDigit,干扰线强度由其内部算法决定,不可调参;若需更强干扰,得换 DriverMath 或自定义 driver。
真正麻烦的从来不是“怎么画一条线”,而是“线画完后,验证码还是否能被用户看清、被服务端正确绑定、被攻击者无法绕过”。Beego 的 captcha 模块省事,但省掉的是安全水位线——换库不难,难的是把 session 绑定、存储替换、缓存头、有效期清理这些链路补全。











