【问题标题】:Is it safe to execute SQL query like this in Python using MySQLdb?使用 MySQLdb 在 Python 中执行这样的 SQL 查询是否安全?
【发布时间】:2012-02-29 09:08:05
【问题描述】:

我注意到大多数消息来源都说在 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 ) )

【问题讨论】:

  • “这对 sql 注入安全吗?”。是的。 “我什至不完全确定在参数化查询中使用 %、,、%s、%d 和 %()s 之间的区别是什么”。这是否意味着您在询问 Python DB-API 的规则?你在问这个python.org/dev/peps/pep-0249吗?

标签: python mysql mysql-python


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    您的插入语句应该明确指定要设置的字段名称,以防止架构更改造成破坏。另外,我发现您的代码太重复了。我会把插入写得更像这样:

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

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

    【讨论】:

    • 我喜欢你使用join()keys() 的方式。感谢您的提示!
    猜你喜欢
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    相关资源
    最近更新 更多