2017-05-23 90 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本身帶有數據佔位符,另一個數據)分別通過網絡傳輸。 –

相關問題