如何在SQLAlchemy(PostgreSQL)的LIKE '%input%'子句中防止SQL注入?
在SQLAlchemy中安全处理含通配符的LIKE查询
你遇到的这个场景很常见:既要让用户输入的%和_作为普通字符精确匹配,又要彻底避免SQL注入,同时让LIKE查询正常工作。你之前写的代码没生效,问题出在参数占位符的写法上——'%:text%'里的:text会被当成字符串的一部分,SQLAlchemy根本不会把它解析成参数,自然匹配不到预期的行。
下面给你两种SQLAlchemy里的惯用解决方案,都能满足你的需求:
方案一:手动转义通配符+参数化拼接
首先我们需要一个小函数,把用户输入里的PostgreSQL LIKE通配符(%、_)转义成字面量,同时还要转义转义符本身(PostgreSQL默认用\作为转义符):
def escape_like_input(value): # 先转义反斜杠,再转义%和_ return value.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
然后在查询时,先转义用户输入,再拼接前后的%,直接传给like()方法——SQLAlchemy会自动把整个拼接后的字符串作为安全参数处理:
safe_input = escape_like_input(user_input) entities = session.query(Entity).filter(Entity.name.like(f"%{safe_input}%")).all()
这样一来,用户输入的%和_会被当成普通字符匹配,同时完全避免了SQL注入风险。
方案二:用SQLAlchemy的func实现SQL层面的拼接
如果你更倾向于在SQL层面处理字符串拼接,可以用SQLAlchemy的func模块调用PostgreSQL的字符串函数,同样先转义用户输入:
from sqlalchemy import func safe_input = user_input.replace("%", "\\%").replace("_", "\\_") entities = session.query(Entity).filter( Entity.name.like(func.concat("%", safe_input, "%")) ).all()
这种方式和方案一本质上是一样的,只是把字符串拼接的逻辑放到了数据库端执行,同样安全可靠。
再说说你原代码的问题
你之前写的:
entities = session.query(Entity).filter(Entity.name.like('%:text%')) \ .params(text=user_input).all()
这里的'%:text%'是一个完整的字符串字面量,SQLAlchemy会直接把它作为LIKE的匹配模式发送给数据库,:text不会被替换成用户输入的内容——相当于你在找名字里包含:text这个字符串的实体,当然匹配不到预期结果啦。
内容的提问来源于stack exchange,提问作者bdesham
相关产品推荐
相关产品推荐

