我目前正在审查某人的代码,遇到了以下Python代码行:
db.query('''SELECT foo FROM bar WHERE id = %r''' % id)
这与我的常识相违,因为我通常会选择使用prepared statements来进行操作,或者至少使用数据库系统的本地字符串转义函数。
然而,我仍然很好奇如何利用它,鉴于以下几点:
- 'id'值是由最终用户/渗透测试人员提供的字符串或数字
- 这是MySQL
- 连接明确设置为使用UTF8。
我目前正在审查某人的代码,遇到了以下Python代码行:
db.query('''SELECT foo FROM bar WHERE id = %r''' % id)
这与我的常识相违,因为我通常会选择使用prepared statements来进行操作,或者至少使用数据库系统的本地字符串转义函数。
然而,我仍然很好奇如何利用它,鉴于以下几点:
MySQL的Python驱动程序不支持真正的预处理语句。它们都使用某种形式的字符串插值。关键是让Python使用适当的转义进行字符串插值。
查看一个不安全的演示:PyMySQL如何防止用户进行SQL注入攻击?
模拟参数的常规解决方案如下:
sql = "SELECT foo FROM bar WHERE id = %s"
cursor.execute(sql, (id,))
请查看https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html
set names utf8
,您应该可以避免此问题。sql_mode
以打破转义,例如启用NO_BACKSLASH_ESCAPES
或ANSI_QUOTES
。您应该在会话开始时设置sql_mode
,类似于设置名称。这将确保它不使用全局更改的sql_mode导致问题。'''SELECT foo FROM bar WHERE id = %r''' % id
吗?到目前为止,我失败了。 - roganjosh%r
调用了 repr(),它与 Python 连接器中的 MySQLConverter 做了大致相同的事情。由于您的字符集是 UTF8,只要在字符串格式化时使用 %r
而不是 %s
,我认为两者都不会有漏洞。 - Bill Karwin
id
做的最好的事情就是检查它是否为整数。在这里,大多数脆弱的方法甚至都不会去做这个检查,所以它们是开放的。 - roganjosh