不能直接拼接用户输入到like语句中,因%、_是通配符且预处理不转义它们;正确做法是用escape子句配合手动转义(如%),并用?占位符传参。

为什么不能直接拼接用户输入到 LIKE 语句中
因为 SQL 注入风险:用户输入 %' OR '1'='1 这类字符串,拼进 WHERE name LIKE '%<user_input>%'</user_input> 后会变成 WHERE name LIKE '%' OR '1'='1%',破坏查询逻辑甚至泄露数据。Golang 的 database/sql 虽能防参数注入,但 LIKE 中的通配符(%、_)本身是 SQL 语法的一部分,预处理语句不转义它们——所以你传进去的 %abc% 会被原样当通配符执行,不是字面量。
正确做法:用 ESCAPE 子句 + 手动转义通配符
核心思路是把用户输入中的 %、_ 和转义字符本身(比如 )全部转义,再用 ESCAPE '' 告诉 SQL 引擎“后面跟 的才是通配符,否则就是普通字符”。
- 选一个不太可能出现在用户输入中的转义字符,
最常用,但若用户真输backslash est,就得先双写成backslash\test - 用
strings.ReplaceAll依次替换:先处理转义符(→\),再处理%(→%),最后处理_(→_) - 拼接时用
?占位符传参,SQL 模板固定为WHERE col LIKE ? ESCAPE ''
func escapeLikePattern(s string) string {
s = strings.ReplaceAll(s, ``, `\`)
s = strings.ReplaceAll(s, `%`, `%`)
s = strings.ReplaceAll(s, `_`, `_`)
return s
}
<p>pattern := "%" + escapeLikePattern(userInput) + "%"
err := db.QueryRow("SELECT * FROM users WHERE name LIKE ? ESCAPE ''", pattern).Scan(&name)
</p>
PostgreSQL 用户注意:ESCAPE 字符必须是单字节且不能是 % _ 或空白
PostgreSQL 对 ESCAPE 更严格:不能用空格、%、_,也不能是多字节字符(如中文)。如果你用 ESCAPE '§',而用户输入含 §,就又得额外转义它——反而更麻烦。所以还是坚持用 ,并确保在 escapeLikePattern 里最先处理它。
- PostgreSQL 8.2+ 支持
ESCAPE,但低版本需改用正则(~)或replace()预处理字段值,不推荐 - 不要用
pgx的QueryRow直接传带的字符串而不转义——它不会帮你做ESCAPE相关处理
更安全的替代方案:用正则或全文检索代替 LIKE
如果业务允许,模糊匹配优先考虑数据库原生能力,避开手写 LIKE 的所有陷阱:
- MySQL:用
REGEXP,参数仍走预处理,通配符在正则引擎内解释,和 SQL 层隔离 - PostgreSQL:用
ILIKE+replace()清洗输入,或直接上to_tsvector/to_tsquery - 简单前缀搜索?直接用
WHERE col >= ? AND col (例如查 <code>abc%→col >= 'abc' AND col ),索引友好且零转义
真正难的是“中间匹配”(如 %abc%)且必须用 LIKE 的场景——这时候逃逸逻辑必须写对,漏掉任意一次 strings.ReplaceAll 顺序都会导致漏洞。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











