2012-01-15 83 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