2012-01-15 33 views
1

我在Python中使用MySQLdb。有人告訴我,正確地創建SQL語句,避免SQL注入攻擊我應該在代碼是這樣的:如何在Python中檢查和執行SQL語句

sql = "insert into table VALUES (%s, %s, %s)" 
args = var1, var2, var3 
cursor.execute(sql, args) 

或者:

cursor.execute("insert into table VALUES (%s, %s, %s)", var1, var2, var3) 

甚至這個(這可能是錯誤的):

header = ('id', 'first_name', 'last_name') 
values = ('12', 'bob'  , 'smith' ) 
cursor.execute("insert into table (%s) values (%s)", (header + values)) 

當我用PHP編程時,我通常會將整個SQL語句存儲爲一個長字符串,然後執行該字符串。喜歡的東西(在PostgreSQL):

$id   = db_prep_string(pg_escape_string($id  )); 
$first_name = db_prep_string(pg_escape_string($first_name)); 
$last_name = db_prep_string(pg_escape_string($last_name )); 

$query = "insert into table (id, first_name, last_name) values ($id, $first_name, $last_name)" 

$result = pg_query($con, $query); 
$retval = pg_fetch_array($result); 

其中db_prep_string

function db_prep_string($value) { 
    if( 
     !isset($value) || 
     (is_null($value)) || 
     preg_match('/^\s+$/', $value) || 
     ($value == '') 
    ) { 
    $value = 'null'; 
} 
else { 
    $value = "'$value'"; 
} 
    return $value; 
} 

然後進行調試,我可以簡單地輸出$query查看整個SQL語句。我可以用Python做類似的事嗎?換句話說,我可以將SQL語句作爲字符串存儲,打印出來進行調試,然後執行它嗎?

我想這樣做:

id   = prevent_sql_injection_string(id  ) 
first_name = prevent_sql_injection_string(first_name) 
last_name = prevent_sql_injection_string(last_name ) 

sql = "insert into table (id, first_name, last_name) values " 
sql += id   + ", " 
sql += first_name + ", " 
sql += last_name 

print sql #for debugging 

cursor.execute(sql)   

如果沒有,那麼我該怎麼辦視圖在Python中全部的SQL語句?

獎金問題:如何在使用Python的SQL語句中輸入空值?

+0

這是使用「參數化」查詢或SQL調用的。 – DOK 2012-01-15 23:16:34

+0

如果你想輸入一個空值,使用'None'。 – MRAB 2012-01-15 23:28:30

+0

你在pgsql查詢中嵌入參數以獲得一個巨大的字符串?呸!即使在PHP中,您也有'pg_query_params',您可以在其中將查詢與值分開。 – ThiefMaster 2012-01-15 23:38:18

回答

3

看看Python Database API specification,因爲它回答了你的一些問題。例如,在空值API規格這樣說:

SQL NULL值由上 輸入和輸出Python的無單表示。

和參數樣式該規範爲實現者提供了多個選項,包括MySQLdb使用的'format'選項。

如果您想查看MySQLdb將針對您的數據庫執行什麼查詢,您可以作弊一點並使用連接literal(...)方法。例如:

>>> import MySQLdb 
>>> db = MySQLdb.connect(...) 
>>> print "insert into table VALUES (%s, %s, %s)" % db.literal((5, "ab'c", None)) 
insert into table VALUES (5, 'ab\\'c', NULL) 

然而db.literal(...)方法是不是真的意味着由MySQLdb的模塊的客戶端使用,所以不要把它在生產代碼。

而且,請注意,MySQLdb documentation有這樣說的參數:

參數佔位符只能用於插入列值。它們不能用於SQL的其他部分,例如表名,語句等。

因此,請小心在插入語句中使用參數佔位符作爲表的列名。

-2

你想要做的代碼是有效的。你可以這樣做:

def prevent_sql_injection_string(value): 
    if (value is None or str(value).strip()=''): 
     value = 'null' 
    else: 
     value = "'%s'" % str(value) 
    return value  

# convert inputs 
id   = prevent_sql_injection_string(id  ) 
first_name = prevent_sql_injection_string(first_name) 
last_name = prevent_sql_injection_string(last_name ) 

# construct query 
# Note: "some formatted string" % (value,value,value) syntax is like doing 
# printf("some formatted string",value,value,value) 
sql = "insert into table (id, first_name, last_name) values (%s, %s, %s)" 
     % (id,first_name,last_name) 

# print 
print sql 

# execute 
cursor.execute(sql) 
+0

雖然沒有人應該這樣做! – ThiefMaster 2012-01-15 23:38:44

+0

你的代碼格式似乎是錯誤的(以':'結尾的第一行之後沒有縮進塊)。另外,我不明白這是如何防止任何事情。如果我保護的字符串中有一個單引號會怎麼樣?你所做的只是添加單引號,所以如果我的值是'''; drop table foo「',是不是會導致問題? – 2012-01-15 23:41:06

+0

請解釋爲什麼不,如果你要downvote - 我很好奇,並誠實想知道。 – 2012-01-15 23:42:10