这个Python/MySQL查询语句容易受到SQL注入攻击吗?

4

我目前正在审查某人的代码,遇到了以下Python代码行:

db.query('''SELECT foo FROM bar WHERE id = %r''' % id)

这与我的常识相违,因为我通常会选择使用prepared statements来进行操作,或者至少使用数据库系统的本地字符串转义函数。

然而,我仍然很好奇如何利用它,鉴于以下几点:

  1. 'id'值是由最终用户/渗透测试人员提供的字符串或数字
  2. 这是MySQL
  3. 连接明确设置为使用UTF8。

1
  1. 'id'由用户提供。
  1. 不同的SQL服务器具有不同的转义机制。
  2. MySQL根据字符集以不同方式进行转义。
- Evert
1
你能为 id 做的最好的事情就是检查它是否为整数。在这里,大多数脆弱的方法甚至都不会去做这个检查,所以它们是开放的。 - roganjosh
1
@roganjosh,抱歉要再次明确。我不是在寻求改进此代码。我会使用预处理语句。我正在寻找证据表明这是可利用的。 - Evert
1
当然,我明白你在问什么。甚至Bobby Tables也足以在这里进行演示 :) - roganjosh
1
@roganjosh 谢谢!非常好奇 :D - Evert
显示剩余5条评论
1个回答

1

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


我所知道的克服转义(当它被正确执行时)的唯一方法是:
  • 利用GBK或SJIS或类似字符集,其中转义引号变成多字节字符的一部分。通过确保set names utf8,您应该可以避免此问题。
  • 更改sql_mode以打破转义,例如启用NO_BACKSLASH_ESCAPESANSI_QUOTES。您应该在会话开始时设置sql_mode,类似于设置名称。这将确保它不使用全局更改的sql_mode导致问题。

另请参阅“mysqli_real_escape_string”足以避免SQL注入或其他SQL攻击吗?


1
这并没有回答问题;我们能够注入到 '''SELECT foo FROM bar WHERE id = %r''' % id 吗?到目前为止,我失败了。 - roganjosh
2
我很感激您提供的背景信息,但我主要是在寻找一种方法来利用上述代码而不进行任何修改。我的角色并不是工程师,而是作为第三方审查人员被雇用的。尽管源代码存在风险,但我仍然想展示一个真正的问题。 - Evert
看起来 %r 调用了 repr(),它与 Python 连接器中的 MySQLConverter 做了大致相同的事情。由于您的字符集是 UTF8,只要在字符串格式化时使用 %r 而不是 %s,我认为两者都不会有漏洞。 - Bill Karwin
@BillKarwin,我想这真的取决于它是否足够好用?它能被破解吗?如果你的答案是“绝对不会”,并且有证据支持,我完全可以接受。如果你不确定,我会再开放一段时间来提问。 - Evert
@Evert,很难证明某些东西无法被利用。我已经在Python聊天室中公开了这个问题,并且有一种方法看起来可以胜任,但我目前想不出为什么你会将其放在后端。 - roganjosh
公平!我想我只是在寻找“某种程度的确定性”。 - Evert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接