用于创建查询的 psycopg2 变量格式

psycopg2 variables format for creating queries

这不是那么相关,所以我只是对以下 (Python 2.7) 感到好奇:

我刚开始使用 psycopg 并通读文档,他们总是使用字符串 (%s) 和元组将值传递给查询。

The variables placeholder must always be a %s

所以考虑下面的例子-

在名为 'test' 且字段为 value_1 (varchar) 和 value_2 (int) 的 table 中,查询创建为:

value_1 = "test"
value_2 = "100"
cur.execute("INSERT INTO test (value_1,value_2) VALUES (%s,%s)",\
           (value_1,value_2))

我的问题是使用 'format' 方法(如下所示)是否是一种不好的做法甚至有问题:

cur.execute("INSERT INTO test (value_1,value_2) VALUES ('{value1}',{value2})".\
           format(value1=value_1,value2=value_2))

根据您的经验,您怎么说,这真的很危险或有问题吗?

来电

cur.execute("INSERT INTO test (value_1,value_2) VALUES (%s,%s)",\
           (value_1,value_2))

有一个字符串参数和一个附加参数,它是用于替换的值的元组。 这允许 psycopg2 插入值,并且比简单的字符串插入更安全。

usage docs for psycopg2

♯ Pass data to fill a query placeholders and let Psycopg perform

♯ the correct conversion (no more SQL injections!)

>>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", ... (100, "abc'def"))

通话中

cur.execute("INSERT INTO test (value_1,value_2) VALUES ('{value1}',{value2})".\
           format(value1=value_1,value2=value_2))

自己插值,只是将结果字符串传递给游标执行方法。

简单插值容易受到 SQL 注入的影响。您最好使用第一种形式。

您应该始终考虑 "Little Bobby Tables"

在阅读了一些文档和源代码并自行测试后,弄清楚了。 简单的回答:这太不安全了。不仅适用于 psycopg2,而且适用于任何数据库模块(至少对于我测试过的模块)。 将此与 psycopg2 相关联,使用 (%s),(variable,) 允许 psycopg2 自动转义这些变量以防止出现此类混乱。

我的测试是为了找出它可能造成的小混乱:

cur.execute("INSERT INTO test (value_1,value_2) VALUES ('{value1}','{value2}')".\
format(value1=value_1,value2='1); drop table test; --killer instinct'))

就是这样,欢迎测试 table :-P

是的,Psycopg2 将 %s 用于所有类型,psycopg2 将参数转换为其字符串表示形式并在查询中使用它

INSERT INTO test (value_1,value_2) VALUES('test','100');

有时您可能需要将某些值转换为适当的类型。

 cur.execute("""INSERT INTO test (value_1,value_2) 
       VALUES (%s,%s::integer)""",
       (value_1,value_2))

您提出的方法是非常糟糕的做法,您已经对 value_1 和 value_2 的几个可能值进行了 sql 注入。例如:

 value_1="',0); rollback; drop table test ; --"

我在 Python 3 和 psycopg2 但是当只插入 1 个值时,不要忘记尾随逗号否则它会抛出 not all arguments converted during string formatting.

所以我的台词是 cur.execute(sql, (plan_name,)) 并不是 cur.execute(sql, (plan_name))