fmt.Sprintf 会将 % 视为格式动词导致 SQL 损坏或注入,应改用参数化查询(如 $1 或 ?)或静态字符串;动态字段名等不可参数化部分须白名单校验。

因为 fmt.Sprintf 会把 % 当成格式动词解析,导致 SQL 被意外截断或注入,且无法防御恶意输入。
fmt.Sprintf 把 % 解析成格式符,不是字面量
PostgreSQL 的 LIKE 查询依赖 % 作为通配符,但 fmt.Sprintf 中孤立的 %(如 "%s%" 里的第二个 %)会被识别为未闭合的格式动词。一旦后续没有匹配参数,就会输出 %!(MISSING) 或直接 panic;传给数据库的 SQL 已损坏,触发类似 pq: syntax error at or near "(" 的错误。
- 错误写法:
fmt.Sprintf("SELECT * FROM t WHERE name LIKE '%s%'", userInput)—— 若userInput是"O'Reilly",拼出的 SQL 是... LIKE 'O'Reilly%'...,单引号不闭合 - 更糟的是:
userInput若含%d或%s,fmt.Sprintf会尝试解析,结果不可控
SQL 注入风险完全失控
fmt.Sprintf 不做任何输入过滤或转义,用户输入直接进入 SQL 字符串。哪怕加了 %% 转义,也只解决 % 问题,对单引号、反斜杠、分号等毫无防护。
- 攻击示例:
userInput = "admin' OR '1'='1"→ 拼出WHERE name LIKE 'admin' OR '1'='1%',绕过条件 - 修复不能靠“多转义几次”,必须剥离执行逻辑与数据边界
database/sql 原生支持参数化,别绕路
标准 database/sql 完全支持 ? 占位符,PostgreSQL 驱动(如 pgx 或 lib/pq)会自动处理类型绑定和转义,% 在参数值里就是纯字符,无需手动处理。
立即学习“go语言免费学习笔记(深入)”;
- 安全写法:
db.Query("SELECT * FROM t WHERE name LIKE $1", prefix+"%")(pgx)或db.Query("SELECT * FROM t WHERE name LIKE ?", prefix+"%")(lib/pq) - 前缀固定就更简单:
db.Query("SELECT * FROM t WHERE name LIKE 'camel.%'")—— 静态字符串,零风险 - 切勿用
fmt.Sprintf拼接字段名、表名、ORDER BY 子句——这些无法参数化,必须白名单校验
真正危险的不是 % 本身,而是把用户输入当作格式串一部分的思维惯性。只要 SQL 中混入任意不可信变量,fmt.Sprintf 就是第一道失守的防线。


















