beego 默认防 sql 注入但需正确使用 orm/raw 参数绑定,xss 防护需手动开启模板转义或调用 html.escapestring;绕过框架机制则所有防护失效。

Beego 默认能防 SQL 注入,但前提是别绕过 ORM 或 Raw 的参数绑定机制;XSS 防护则需手动开启模板自动转义或显式调用 html.EscapeString,否则不生效。
beego ORM 和 Raw 查询如何防 SQL 注入
beego 的 ORM 和 Raw 方法底层全部走 Prepare Statement,参数通过绑定(? 占位符)传入,SQL 解析与参数值分离,天然阻断拼接型注入。但这个保护只在你“正确使用”时起作用。
- ✅ 正确写法:
o.Raw("SELECT * FROM user WHERE id = ?", userID).QueryRows(&users) - ❌ 错误写法:
o.Raw("SELECT * FROM user WHERE id = " + strconv.Itoa(userID)).QueryRows(&users)—— 字符串拼接直接废掉所有防护 - ⚠️ 注意:
Raw中的?占位符数量必须和参数个数严格一致,多或少都会 panic,不是静默失败 - ? beego 不支持命名参数(如
:id),只认?,且不支持在IN子句里直接绑数组(得手动生成等长的?, ?, ?并逐一传参)
为什么绕开 ORM 用原生 database/sql 就容易中招
beego 自身不接管你手动引入的 database/sql 实例。如果你在 controller 里自己 sql.Open、db.Query,又用 fmt.Sprintf 拼 SQL,那 beego 的任何安全机制都无效。
- 常见场景:导出报表时动态拼
WHERE条件、批量插入时手写多值INSERT - 性能陷阱:每次
db.Query都新建 stmt,MySQL 侧 Prepare Statement 数会飙升(参考 beego stmt 优化文档) - 解决思路:优先复用 beego ORM 的
QueryTable或封装一个带参数绑定的查询工具函数,避免裸写db.Query
模板层 XSS 防护不是默认开启的
beego 的模板引擎(html/template)本身支持自动 HTML 转义,但必须满足两个条件:变量输出用双花括号 {{.Name}},且该字段类型是 string(不是 template.HTML)。一旦你用 {{.Name|safe}} 或显式转成 template.HTML,就跳过转义。
- ✅ 安全输出:
{{.UserInput}}→ 自动转义<script></script>为<script></script> - ❌ 危险输出:
{{.UserInput|safe}}或{{template.HTML .UserInput}}→ 原样渲染,XSS 可执行 - ? 若需部分信任内容(如富文本),应使用白名单过滤库(如
bluemonday)预处理,再传入模板,而不是依赖|safe - ⚠️ 注意:
context.Output.Body()直接写响应体时,完全绕过模板转义,必须自行调用html.EscapeString
CSRF 和其他防护项要不要开
CSRF 保护在 beego 中是默认启用的(EnableCsrf = true 在 app.conf),但仅对非 GET/HEAD 请求生效,且要求前端在表单里嵌入 {{.CSRFToken}} 或在 AJAX header 中带 X-CSRF-Token。XSS 和 SQL 注入是代码层责任,CSRF 是协议层配合问题。
- CSRF Token 有效期默认 1 小时,超时后提交会 403,不要在长表单页缓存 token 太久
-
AutoRender = false时,{{.CSRFToken}}不可用,需手动从ctx.Input.CSRFToken()取 - API 场景若用 JWT 认证,CSRF 通常可关(
EnableCsrf = false),但要确认没混用 Cookie 认证
最易被忽略的一点:安全机制只覆盖框架“标准路径”,一旦你用 http.HandleFunc 注册裸路由、或在 Controller.Prepare() 里直接读 ctx.Input.RequestBody 后拼 SQL、或把用户输入不经转义塞进 js 字符串里,所有防护就形同虚设。











