为什么SQLite3参数化查询在LIKE语句中不会自动转义通配元字符?
核心原因
SQLite的参数化查询仅负责转义SQL语法层面的特殊字符(比如单引号、语句分隔符这类会破坏SQL结构、引发注入风险的字符),不会自动处理LIKE子句下的专属通配符。
参数化的设计边界是保证传入参数不会被解析为SQL指令的一部分,不会识别你SQL中具体使用了什么操作符、操作符本身有什么特殊语义规则,所以传入的_和%进入LIKE表达式后,依然会被按照通配符规则解析,这不是参数化失效,是功能边界本来就不覆盖这部分逻辑。
这也解释了为什么等值查询WHERE column = ?没有问题:=操作符本身不存在通配符语义,所有传入字符都会被当做普通字面量处理,自然不需要额外转义。
实现方案
不需要在Python层额外编写独立的转义校验函数,直接利用SQLite原生支持的LIKE自定义转义符能力,把转义逻辑内嵌在SQL语句中即可,完全适配现有参数化传值的写法。
修正后的代码如下:
con = sqlite3.connect('database.db') cursorObj = con.cursor() # 声明!为转义符,在SQL内部完成通配符转义 sqlStatement = """ SELECT * FROM usertable WHERE username LIKE '%' || replace(replace(replace(?, '!', '!!'), '%', '!%'), '_', '!_') || '%' ESCAPE '!' """ cursorObj.execute(sqlStatement, ("_", )) rows = cursorObj.fetchall()
逻辑说明:
- 转义逻辑全部在SQL语句内部通过内置
replace函数实现,不需要在数据库逻辑外写额外处理代码 - 优先替换转义符本身
!为!!,避免参数本身携带!时转义逻辑错乱 - 再将参数内的
%替换为!%、_替换为!_,配合ESCAPE '!'声明后,这两个字符会被识别为普通字面量,不再触发通配符匹配 - 全程使用参数化传值,不会引入SQL注入风险
不要在Python层提前做字符串替换拼接参数,将转义逻辑放在SQL侧实现,既可以避免多场景复用时漏转义的问题,也能和现有加密存储、解密读取的逻辑完全解耦。
内容的提问来源于stack exchange,提问作者noNameNitwit
相关产品推荐
相关产品推荐

