【问题标题】:psycopg2 variables format for creating queries用于创建查询的 psycopg2 变量格式
【发布时间】:2015-01-23 22:59:45
【问题描述】:

这无关紧要,所以我只是对以下内容感到好奇(Python 2.7):

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

变量占位符必须始终为 %s

所以考虑下面的例子-

在一个名为“test”的表中,包含字段 value_1 (varchar) 和 value_2 (int) 的查询被创建为:

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

我的问题是,改用“格式”方法是否是一种不好的做法或什至有问题(如下):

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

根据您的经验,您认为这真的很危险或有问题吗?

【问题讨论】:

    标签: python postgresql psycopg2


    【解决方案1】:

    在阅读了一些文档和源代码并自行测试之后,我明白了这一点。 简单的回答:这该死的不安全。不仅适用于 psycopg2,而且适用于任何 db 模块(至少对于我测试过的那些)。 将此与 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'))
    

    就是这样,再见测试表:-P

    【讨论】:

      【解决方案2】:

      电话

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

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

      usage docs for psycopg2

      &尖锐;传递数据以填充查询占位符并让 Psycopg 执行

      &尖锐;正确的转换(不再有 SQL 注入!)

      >>> 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"

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          是的,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 ; --"
          

          【讨论】:

            猜你喜欢
            • 2012-09-28
            • 1970-01-01
            • 1970-01-01
            • 2018-02-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-18
            • 1970-01-01
            相关资源
            最近更新 更多