mysql中escape仅用于like查询中转义%和_等通配符,需配合escape关键字指定转义字符,如like '/_hello' escape '/'使下划线匹配字面值而非通配符。

escape 和 escapeId 是 my/mysql 客户端库里唯二真正可用的转义入口,但它们只在特定场景下有效——直接拼接 SQL 字符串时。绝大多数情况下,你不该用它们。
什么时候必须用 escape?
仅限于无法使用参数化查询的极少数边缘情况,比如动态构造 WHERE 条件中的字符串值(且不能用占位符),或调试时临时打印 SQL。
-
escape只处理字符串字面量,对数字、布尔值、NULL 不做任何转换 - 它会把
'变成\'(MySQL 模式)或''(PostgreSQL 不兼容) - 如果输入是
"O'Reilly",输出是"'O\'Reilly'",多一层引号包裹 - 错误用法:
connection.escape("user_input") + " AND status = 1"—— 后半段仍可注入
escapeId 只能用于表名、列名、数据库名
动态表名、排序字段、GROUP BY 列这些无法参数化的部分,必须走 escapeId,而不是手写引号或拼接。
-
escapeId("user_table")→<code>user_table -
escapeId("user.name")→<code>user.name -
escapeId("order")→<code>order(自动加反引号防关键字冲突) - 禁止用于值:
escapeId("admin' --")输出<code>admin' --,依然可注入
单纯转义特殊字符在搜索框里根本不可靠
搜索框常见错误是把 addslashes() 或前端 replace(/'/g, "''") 当成防线。
- MySQL 宽字节注入(如
%df%27)会让addslashes()失效 -
LIKE子句里的%和_不是 SQL 元字符,但攻击者会混用:test' OR 1=1 -- - URL 编码、零宽空格、BOM 头未解码就转义,等于白做
- 正确做法:强制用
LIKE ?占位符,再由驱动绑定完整值(如%${keyword}%),不拼接
参数化查询才是唯一可靠路径
escape 和 escapeId 都是补救措施,不是设计原则。
- 所有用户输入进 WHERE、INSERT、UPDATE 的值,必须走
?或命名参数(如:kw) - MyBatis 用
#{},PDO 用bindValue(),SQLAlchemy 用filter(...like(...)) - 动态表名/列名必须配白名单校验,例如:
if (!['users', 'posts'].includes(tableName)) throw Error('invalid table')
真正容易被忽略的点是:转义函数本身不解决上下文混淆。同一个字符串,在值位置要 escape,在标识符位置要 escapeId,在 JSON 字段里可能还要 JSON.stringify() —— 混用就会漏防。










