为什么PyMySQL不易受到SQL注入攻击



我是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中正确处理它们,期待着参数替换的方法,但令我惊讶的是,我什么都找不到。相反,我发现的每个线程都使用了字符串操作(例如,here、here、where和here(附带一条注释,声称字符串操作将是PyMySQL的标准操作(。

这对我来说很有趣,因为我以前只处理过SQLite,其中DBAPI文档明确警告要对变量使用字符串操作:

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

文档用以下代码片段举例说明了这一点:

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

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

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

为什么在sqlite3中使用字符串操作容易受到SQL注入攻击,而在pymysql中却没有受到质疑?

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

它不仅仅是做一个简单的字符串替换。Pymysql在将值插入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()的代码解决了这个问题。

相关内容

  • 没有找到相关文章