2010-11-06 61 views
2

好的,我正在創建與遊戲服務器一起使用的函數。該服務器使用插件。我有這些函數,使用sqlite數據庫,以及apsw檢索另一個函數存儲的項目。我有3個問題。3涉及python和sqlite的問題

問題一:我總是收到錯誤「SQLError:near」?「:語法錯誤」由於我的語句具有多重?,因此證明嚴重錯誤,所以錯在哪裏?

問題二:我知道SQL注入,但是這些函數只從腳本的運行者那裏獲得輸入,而他會破壞的唯一東西是他自己的。即便如此,有沒有一種簡單的方法來做這個SQL注入證明?

問題三:有什麼辦法可以讓這個功能更高效嗎?

下面是函數: 編輯:繼承人是什麼樣子現在:

def readdb(self,entry,column,returncolumn = "id,matbefore,matafter,name,date"): 
    self.memwrite 
    if isinstance(entry, int) or isinstance(entry, str): 
     statement = 'SELECT {0} FROM main WHERE {1} IN {2}'.format(returncolumn,column,entry) 
     self.memcursor.execute(statement) 
     blockinfo = self.memcursor.fetchall() 
     return(blockinfo) 
    if isinstance(entry, tuple) or isinstance(entry, list): 
     statement = '''SELECT {0} FROM main WHERE {1} IN (%s)'''.format(returncolumn,column) 
     self.memcursor.execute(statement % ("?," * len(entry))[:-1], entry) 
     blockinfo = self.memcursor.fetchall() 
     return(blockinfo 
+0

一些更正您對您的代碼:使用'如果isinstance(入門,INT)或isinstance(入境,STR)'。或者至少'如果vartype在[int,str]'中。 '如果vartype == int或str'不會達到你所期望的。還要記住當你不想傳遞任何參數時用'()'調用函數,例如。 'return self.memcursor.fetchall())'。否則,您將返回對該函數的引用,而不是調用它。 – 2010-11-06 19:49:05

+0

另外在Python 2中,最好使用basestring而不是str,因爲basestring是str和unicode的父類。同樣,你可能會傳遞一個long或int,所以尋找兩者。 – 2010-11-20 04:53:46

回答

3

這是有趣的(閱讀,瞭解原因)。

第一條語句實際上使用了sqlite3 -module的值綁定機制(我假設這是你使用的)。因此,*(這是默認列)會被轉義,從而使該語句無效。這是SQL注入證明,並且您自己的代碼嘗試注入SQL(請參閱現在有趣?)。

第二次使用Pythons字符串替換爲了構建查詢字符串,這不是SQL注入證明。

0

使用名稱獲取更多信息性錯誤消息。例如,我特意留出這個逗號:

cur.execute("select ? ?,?", (1,2,3)) 
SQLError: near "?": syntax error 

現在用的名字:

cur.execute("select :1 :2,:3", (1,2,3)) 
SQLError: near ":2": syntax error 

如果你有大量的綁定我建議你切換到指定的綁定風格和傳遞字典爲綁定本身。

cur.execute("select :artist, :painting, :date", 
    {"artist": "Monster", "painting": "The Duck", "date": "10/10/2010" }) 

您只能使用綁定的值而不是列或表名。有幾種可能的方法。雖然SQLite支持任意列/表名,但您可以要求它們只有ASCII字母數字文本。如果你想減少限制,那麼你需要引用名字。圍繞在其中帶有雙引號的名稱使用方括號,並在帶有方括號的名稱周圍使用雙引號。名字不能同時具有。

所有使用授權者機制的替代方案。請參閱Connection.setauthorizer以獲取API和指向示例的指針。簡而言之,你的回調函數將會被調用,所以你可以拒絕寫入數據庫的任何東西。

就效率而言,您可以根據調用者如何使用結果來改進。遊標很便宜。沒有必要一遍又一遍地重複使用同一個文件,這樣做會導致細微的錯誤。當你要求時,SQLite只會得到結果的下一行。通過使用fetchall你堅持建立一個所有結果的列表。如果名單可能很大,或者您可能會中途停止,那麼只需返回db.cursor().execute("... query ...")即可。然後調用者應該用你的功能迭代:

for id,matbefore,matafter,name,date in readdb(...): 
    ... do something ... 

在你的地方,我只想徹底垃圾級這個readdb功能,因爲它不會增加任何價值,並直接編寫查詢:

for id,foo,bar in db.cursor().execute("select id,foo,bar from .... where ...."): 
    ... do something ... 

您的編碼風格表明你對Python相當陌生。我強烈建議查找迭代器和生成器。這是一種簡單得多的編碼風格,可以根據需要生成和消費結果。

順便說一句,這個SQL創建一個長度爲零的表和名爲雙引號和分號的列。 SQLite的功能很好,但不要這樣做:-)然而,它對測試非常有用。

create table "" (["], ";"); 

披露:我是APSW筆者