使用MySQLdb在Python中执行这样的SQL查询是否安全?

时间:2012-02-07 22:07:02

标签: python mysql mysql-python

我注意到大多数消息来源说在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 个答案:

答案 0 :(得分:3)

用于将参数传递给sql命令字符串的方式取决于数据库(例如,sqlite使用?)。

根据MySQLdb documentation,您可以使用paramstyle参数设置格式化字符串的首选方式(formatpyformat)。

您的问题中的第一个示例似乎不受支持。无论如何,我会说,只要你不像上一个例子那样格式化整个字符串,你就可以安全,因为可以假设查询参数将被正确转义。

答案 1 :(得分:1)

您的insert语句应该明确指定要设置的字段名称,以防止从架构更改中断。此外,我发现你的代码太重复了。我会写插入更像这样的东西:

cursor.execute \
  (
        "insert into "
    +
        TABLE_BIZ_NAME
    +
        "("
    +
        ", ".join(biz_info.keys())
    +
        ") values ("
    +
        ", ".join(("%s",) * len(biz_info))
    +
        ")",
    biz_info.values()
  )

这样,在创建biz_info dict时,只需要列出一次字段名称。任何未来的变化只需要在那里进行更新。