【问题标题】:Why is PyMySQL not vulnerable to SQL injection attacks?为什么 PyMySQL 不易受到 SQL 注入攻击?
【发布时间】:2022-01-16 16:58:54
【问题描述】:

我是 PyMySQL 的新手,只是尝试执行一个查询:

c.execute('''INSERT INTO mysql_test1 (
                                    data,
                                    duration,
                                    audio,
                                    comments
                                ) VALUES (
                                    ?,
                                    ?,
                                    ?,
                                    ?
                                );
                            ''', [
                                    comments_var,
                                    duration_var,
                                    audio_var,
                                    comments_var    
                                ]
                            );

但是,它抛出了以下错误:

TypeError: not all arguments converted during string formatting

我注意到我的变量一定有问题,并阅读了如何在 PyMySQL 中正确处理它们,期待参数替换的方法,但令我惊讶的是,我找不到任何东西。相反,我发现的每个线程都使用了字符串操作(例如herehereherehere(有评论声称字符串操作将是 PyMySQL 的标准)。

这对我来说很有趣,因为我以前只处理过 SQLite,其中 DBAPI 文档 explicitly warns 使用带变量的字符串操作:

SQL 操作通常需要使用 Python 变量中的值。但是,请注意使用 Python 的字符串操作来组装查询,因为它们容易受到 SQL 注入攻击。

文档用以下代码 sn-p 举例说明了这一点:

Never do this -- insecure!
symbol = 'RHAT'
cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
Instead, use the DB-API’s parameter substitution.

在阅读PyMySQL docs 时,我找不到任何关于此类危险的提及。它只是证实了我之前的发现:

如果 args 是一个列表或元组,%s 可以用作查询中的占位符。如果 args 是 dict,则 %(name)s 可以用作查询中的占位符。

为什么在sqlite3 中使用字符串操作被认为容易受到 SQL 注入攻击,同时在 pymysql 中不受质疑?

【问题讨论】:

    标签: python mysql sql-injection pymysql string-operations


    【解决方案1】:

    可惜pymysql的设计者选择使用%s作为参数占位符。它使许多开发人员感到困惑,因为这与字符串格式化函数中使用的%s 相同。但它在 pymysql 中并没有做同样的事情。

    这不仅仅是做一个简单的字符串替换。 Pymysql 将 escaping 应用于值,然后将它们插入 SQL 查询。这可以防止特殊字符更改 SQL 查询的语法。

    事实上,你也可以使用 pymysql 遇到麻烦。以下是不安全的:

    cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
    

    因为它在将变量symbol 作为参数传递给execute() 之前将其插入到字符串中。唯一的参数是一个完整的 SQL 字符串,其中包含格式化的变量。

    虽然这是安全的:

    cur.execute("SELECT * FROM stocks WHERE symbol = %s", (symbol,))
    

    因为它将包含symbol 变量的列表作为第二个参数传递。 execute() 函数中的代码对列表中的每个元素应用转义,并将结果值插入到 SQL 查询字符串中。请注意,%s 不是由单引号分隔的。 execute() 的代码负责处理。

    【讨论】:

      猜你喜欢
      • 2015-10-03
      • 2019-08-10
      • 2016-01-02
      • 2013-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-09
      • 2015-03-26
      相关资源
      最近更新 更多