创建元组时如何避免逗号?

时间:2017-06-14 08:52:15

标签: python postgresql

我的python代码中有以下查询:

query = """SELECT id
           FROM dings_archive
           WHERE doorbot_id IN {doorbot_ids};
        """

query = query.format(doorbot_ids=tuple(doorbot_ids))

doorbot_ids的类型为List[int],当我的数组只包含1个元素时,我遇到了问题,因为在query.format后我有以下查询:

SELECT id
FROM dings_archive
WHERE doorbot_id IN (123,);

如你所见,我有一个错误,因为最后有逗号,。如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

为了防止SQL注入,你不应该使用自动将元组转换为字符串(你当前正在做什么),或者在将值传递给驱动程序之前手动加入值列表。

您目前正在利用一个元组转换为字符串产生合理结果的事实:

str((1, 2))
# '(1, 2)'

但正如您所注意到的,单个元素元组会产生语法错误:

str((1, ))
# '(1,)'

有些人建议手动连接列表:

','.join((1, 2))
# '1,2'

也适用于单个元素元组:

','.join((1,))
# '1'

然而这打开了SQL注入的大门,因为逗号实际上是MySQL的控制语句,而不仅仅是一个值。因此,如果有人能够在您的列表中隐藏控制语句,他们可以注入代码:

','.join((1,'1) OR 1=1 --'))
# '1,1) OR 1=1 --'

为了安全抵御此类攻击,您应准备一个查询,其占位符与ID列表中的元素完全相同:

doorbot_ids = [1, 2]

query = "SELECT id FROM dings_archive WHERE doorbot_id IN ({});".format(','.join(['%s'] * len(doorbot_ids)))

这将返回一个新查询,其中包含所需的几个占位符:

'SELECT id FROM dings_archive WHERE doorbot_id IN (%s,%s);'

然后每个占位符都填充一个值:

query = cursor.execute(query, doorbot_ids)

答案 1 :(得分:0)

不要将列表转换为元组,直接使用它:

query = """SELECT id
           FROM dings_archive
           WHERE doorbot_id = any(%s);
        """
...
cursor.mogrify(query, (doorbot_ids,))