当使用redis-py客户端对用户提供的
query_str
(不是Redis query
参数格式,而是要搜索的文本本身)执行全文搜索时仅在特定字段 text
在 Redis Stack 服务器上,我担心使用字符串插值会使自己暴露于查询注入。那么在这种情况下避免查询注入的最佳实践是什么?
准确来说,对于客户端来说,这个问题应该是与语言无关的,但我会专门用Python来演示这个问题。
from redis import Redis
from redis.commands.search.query import Query
client = Redis.from_url("redis://localhost:6379")
def search_1(query_str: str):
query = Query(f"@text:{query_str}")
return client.ft("idx:test").search(query)
def search_2(query_str: str):
params = {"query_str": query_str}
query = Query("@text:$query_str").dialect(2)
return client.ft("idx:test").search(query, params)
在
search_1()
中,query_str
直接连接到 query
命令的
FT.SEARCH
参数。因此,假设用户提供了 query_str = "query_for_text @other_field:query_for_other_field"
,实际执行的命令将类似于 FT.SEARCH "@text:query_for_text @other_field:query_for_other_field"
。因此,它偏离了我的规范,只在字段text
上执行搜索,并且还搜索另一个字段。
我相信
search_2()
,利用PARAMS
的FT.SEARCH
参数可以解决这个问题。关于 FT.SEARCH
的 PARAMS
文档中指出
搜索查询中对参数名称的每个此类引用都将替换为相应的参数值。
和
您不能在查询字符串中引用不允许具体值的参数,例如在字段名称中,例如
。@loc
虽然文档对此不是很明确,但我认为“替换”并不意味着字符串插值,而是将特定参数的整体视为整个“短语”进行搜索,这也得到了证实我的实验。 我想确认是否是这样。
我确实看过Redis安全性和是否可以对redis查询运行字符串注入攻击?。我相信我的问题与Redis协议防止的注入不同,我将其理解为防止Redis客户端发送到服务器的消息中的注入(用户在输入中输入转义字符假设Redis协议使用转义字符,这它没有)。
在a Github Issue中,除了使用
PARAMS
之外,还有手动转义输入query_str
的解决方案。因此,处理用作查询一部分的未经消毒的用户输入的最佳实践是什么?
f"@text:({query_str})"
(并包含括号)。query_str = query_str.replace('(', '').replace(')', '')
DIALECT 2
使用
DIALECT 2
,文本表达式括号内不允许有其他子查询。查询只能是术语的交集或并集。
通过去掉任何括号,您就消除了有人会这样做的可能性 尝试使用像
opener) @injection:... (closer
这样的命令。
除此之外,您应该进一步解析用户输入。如果不解析用户的输入,很难相信用户输入会与他们想要查找的内容相匹配。您是否想在术语之间添加
|
以匹配至少包含其中一个而不是全部的任何文档?您是否应该将某些术语标记为可选,以便在文档中缺少这些术语时不会取消它们的资格?