在Python中使用MySQLdb执行这样的SQL查询安全吗?
我注意到大多数资料都说,在Python中执行SQL语句的最佳做法是这样的:
cursor.execute( 'select * from coworkers where name = :1 and clue > :2', [ name, clue_threshold ] )
其他资料则说
cursor.execute( "select * from coworkers where name = %s and clue > %s", ( name, clue_threshold ) )
我觉得这两者挺相似的。
无论如何,我一直在做的是创建一个字典来存储值。例如,最初的字典 biz_info
看起来是这样的:
biz_info = {
'business' : None,
'name' : None,
'neighborhood' : None,
'address' : None,
'city' : None,
'state' : None,
'zip_code' : None,
'latitude' : None,
'longitude' : None,
'phone' : None,
'url' : None,
'yelp_url' : None,
}
然后我像这样执行SQL语句
execute_sql( cur, "insert into " + TABLE_BIZ_NAME + """ values (
NULL,
%(name)s,
%(neighborhood)s,
%(address)s,
%(city)s,
%(state)s,
%(zip_code)s,
%(latitude)s,
%(longitude)s,
%(phone)s,
%(url)s,
%(yelp_url)s,
NULL
)"""
, biz_info )
这样做能防止SQL注入吗?我想用字典来存储信息,因为这样管理起来更简单。
说实话,我甚至不太确定在参数化查询中使用 %
、,
、%s
、%d
和 %()s
之间有什么区别。基本上我只知道不要使用
cursor.execute( "select * from coworkers where name = '%s' and clue > %d" % ( name, clue_threshold ) )
2 个回答
1
你的插入语句最好明确指定要设置的字段名称,这样可以防止因为数据库结构的变化而导致的问题。此外,我觉得你的代码有点重复。我会把插入语句写得更像这样:
cursor.execute \
(
"insert into "
+
TABLE_BIZ_NAME
+
"("
+
", ".join(biz_info.keys())
+
") values ("
+
", ".join(("%s",) * len(biz_info))
+
")",
biz_info.values()
)
这样一来,字段名称只需要在创建 biz_info 字典的时候列出一次。将来如果有任何变化,只需要在这里更新就可以了。
3
传递参数给SQL命令字符串的方式取决于你使用的数据库(比如,sqlite使用?
作为占位符)。
根据MySQLdb的文档,你可以使用paramstyle
这个参数来设置你喜欢的字符串格式方式(可以是format
或者pyformat
)。
你问题中的第一个例子似乎不被支持。不过,我想说的是,只要你不是像最后一个例子那样格式化整个字符串,你就没问题,因为可以假设查询参数会被正确处理。