2017-05-23 38 views
1

我有类似下面的代码:使用locals()将参数传递给SQL查询是否安全?

var1 = 1 
var2 = 2 
cursor.execute("INSERT INTO mytable VALUES (:var1, :var2)", {'var1': var1, 'var2': var2}) 

是否有任何理由,我应该用字典文字来传递参数,而不是简单地做这样的:

var1 = 1 
var2 = 2 
cursor.execute("INSERT INTO mytable VALUES (:var1, :var2)", locals()) 

这种感觉更简单,更可以维持,但我不能动摇这里有某种安全气味的感觉。

+0

如果查询是硬编码的,这并不是很糟糕。除非您的DBAPI库真的很可怕,否则您不会传递任何未在网上查询中命名的内容。 –

+0

使用此方法可能会使不必要的数据进入数据库。使用字典可以更好地控制插入的内容。对你来说这可能很清楚,但只要有人开始使用你的代码,就可能发生意外的坏事。 – thepieterdc

+0

...实际上,我*已*看到一些非常糟糕的DBAPI库;你可能想用wireshark进行实际审计。 –

回答

3

这不是一个安全问题(除非你不清理查询字符串本身)。

这是一个维护问题:

  1. 你传递“一切”,所以写得不好查询(即,你一个错字)可能会选择一个意外的值了当地人的()。通过更明确的说法,你更有可能接受这一点。
  2. 你并没有确切地告诉“未来的程序员”你的查询使用了什么,所以有人可能会在你的SQL调用之前改变参数的值,导致意想不到的行为。

在一个简短的查询(如你的例子)使用locals()不是这样的悲剧。使用更复杂的查询,如(这是我抢了我最近的emacs缓冲区):

WITH RECURSIVE 
include_parents(a_id, parent_id, uid, distance) AS ( 
    SELECT accounts.a_id, 
     CASE WHEN admin_can_add THEN NULL 
     ELSE accounts.parent_id END AS parent_id, 
     uid, 0 AS distance 
    FROM accounts LEFT OUTER JOIN account_users 
     ON (accounts.a_id = account_users.a_id AND admin_can_add) 
    WHERE accounts.a_id = $a_id 
    UNION ALL 
    SELECT accounts.a_id, 
      CASE WHEN admin_can_add THEN NULL 
      ELSE accounts.parent_id END as parent_id, 
      account_users.uid, distance + 1 as distance 
    FROM accounts LEFT OUTER JOIN account_users 
      ON (accounts.a_id = account_users.a_id AND admin_can_add), 
      include_parents 
    WHERE accounts.a_id = include_parents.parent_id 
) 
SELECT a_id, uid, distance from include_parents 
     WHERE uid IS NOT NULL 

在这种情况下,通过{'a_id': 14}使得它更清晰的充分的程度,我通过什么,而不是locals()。另外,如果我的查询炸弹寻找另一个我忘记通过的参数(也许是因为我稍微改变了这个查询的用法),它会迫使我更仔细地查看我的代码。如果我通过locals(),查询可能会以我不打算的方式“成功”。

+0

1.是否有可能通过必须输入我的字段列表三次来进行拼写错误? 2.有什么比在查询中编写我在查询中使用的字段更清晰的? – jl6

+0

@ jl6,您是否期望IDE或像pylint或pychecker这样的工具能够解析您的SQL查询字符串并告诉您的变量在哪里使用?在明确使用这些工具时,这些工具会表现得更好。 –

-3

如果您使用Python 3.6,则可以使用f-string interpolation

var1 = 1 
var2 = 2 
cursor.execute(f"INSERT INTO mytable VALUES (:{var1}, :{var2})") 
+1

这是针对SQL注入漏洞量身定制的。数据必须**只能从代码本身带外传递。 Oblig:http://bobby-tables。com/ –

+0

我不是专家,但我认为一般的规则是让sql库进行格式化,因为它需要注意正确和安全地转义变量 – DavidW

+0

有数据库很难做到这一点(* ahem * MySQL * ahem *),但通用规则是保持代码和数据彼此带外,所以通过设计良好的有线协议,SQL库甚至不会执行格式*,而是传递多个不同的字段(一个用于SQL本身带有数据占位符,另一个数据)分别通过网络传输。 –