【问题标题】:MySQL - is it safe to check the 6 first characters of a query to be sure it is a SELECT?MySQL - 检查查询的前 6 个字符以确保它是 SELECT 是否安全?
【发布时间】:2014-05-07 13:13:49
【问题描述】:

我的一个同事写了一些非常糟糕的东西。 我们的老板希望能够从我们网站的后台编写任何 SELECT 查询,然后以 CSV 格式获取结果。

这些查询将由我们的 PRODUCTION MySQL 集群执行。 此后台功能应拒绝任何非 SELECT 查询。

所以他想出了一个非常幼稚的解决方案。 这是PHP代码:

function checkQuery()
{
        $sQuery = trim($_POST['query']);
        if (empty($sQuery))
                return false;
        $sCmd = substr($sQuery, 0, 6);
        if (strtolower($sCmd) != 'select')
                return errorDiv('Only SELECT queries are authorized');
        return $sQuery;
}

对于不懂 PHP 的人,这段代码会从 SQL 查询字符串的开头和结尾删除空格,然后获取前 6 个字符,将它们转换为小写字符,如果不匹配 (erf.. . 松散匹配) 'select',查询被拒绝。

对我来说,这看起来很糟糕,很恶心。 我试图说服他至少创建另一个具有有限权限的 MySQL 用户,但他懒得这样做。

但是我无法证明他可以进行某种黑客攻击。

他使用 mysql_query() 来运行查询字符串,这个驱动程序一次拒绝多个查询。 我找不到任何真正的漏洞利用,但我认为至少有 50% 的可能性会发生不好的事情。

也许一些 NUL 字符或一些模糊的 utf-8 字符可以解决问题?

【问题讨论】:

  • 我认为“select * from sys.object; drop table XXXX”会造成一些损害
  • @GunnarKnudsen: mysql_query() 最多只能执行一个查询。
  • “我试图说服他至少创建另一个 MySQL 用户,但权限有限,但他懒得这么做。”我会考虑辞职,并在一个更有能力、更专业的环境中工作。在我看来,这是解决这里基本技术问题的唯一方法。
  • 其实我知道应该如何干净安全地完成,我要问的是如何破解当前的解决方案,之前部署这个丑陋的东西,所以我可以停止它。
  • @Vesper,MySQL 不支持SELECT ... INTO TABLE

标签: php mysql sql


【解决方案1】:

此功能的正确方法(如果您不能说服他这是一个坏主意)是以受限 MySQL 用户身份运行查询。仅授予该用户 SELECT 权限。如果需要,您还可以限制表集。

【讨论】:

  • 还限制运行存储过程/函数?
【解决方案2】:

我看不出有任何方法可以绕过您同事的checkQuery 例程。如果您不在 PHP 中使用 mysql_* 函数,这将是微不足道的,但由于它们只允许执行单个语句,因此它们至少不会受到诸如 Little Bobby Tables 类型的攻击这样的经典攻击。事实上,这也是mysql_*mysqli_* 中的标准查询函数允许多条语句的关键原因之一(这在mysqli Multiple Statements documentation 中有描述。)

我查看了其他路线,我很满意您同事的代码确实确实有效。 (有一种产生误报的方法,例如即使在有效的 SELECT 查询上也触发检测,但这对您来说没有多大用处。)只要您没有将数据更改为副作用的函数,它就应该'除了SELECT 之外,不能用以SELECT... 开头的语句做任何事情。

可以使用SELECT ... INTO OUTFILE 将新文件写入服务器。这仅限于新文件,因此您无法破坏 /etc/passwd 或其他任何内容,但存在危险。

我能看到的最危险的情况是,如果您的 MySQL 服务器与您的 PHP 服务器是同一台机器,您的 MySQL 用户可以写入您的 PHP 目录,并且您使用的用户具有 FILE 权限。在这种情况下,精心设计的SELECT ... INTO OUTFILE 遵循以下原则:

SELECT '<?php echo \'DANGER WILL ROBINSON!\';' INTO OUTFILE '/Users/matt/Sites/dangerous.php'

可能允许某人创建一个新的 PHP 文件,然后浏览该文件即可执行该文件,此时某人可以执行任意 PHP 代码。我在本地测试了这个潜在的利用,在授予用户 SELECT 和 FILE 权限并允许 MySQL 对我的 wwwroot 进行写访问后,我可以成功地创建一个包含上述代码的 PHP 文件并在我的浏览器中执行它。

除了沿着特定线路的攻击(如果您当前使用的用户没有 FILE 权限,这可能是不可能的),我看不出有多大的危险。我知道这对您没有多大帮助,但它似乎确实是您问题的答案。

但是,我仍然强烈建议您使用 MySQL 身份验证和安全性来为此应用程序创建一个只有 SELECT 权限的新用户。这是内置的、数据库级别的、完全标准的、经过充分验证和测试的解决问题的方法,并且限制了未来潜在的问题。

例如,如果有人以其他方式入侵您的 PHP 服务器,只要能够读取您的 MySQL 用户的密码,他们就可以访问具有高权限的经过身份验证的用户,他们可以将其用于其他攻击(也许通过将他们自己的脚本扔到您的 PHP 服务器上并运行它们。)如果 MySQL 用户是 SELECT-only,即使您的 PHP 服务器被完全破坏,这也会限制对您的数据/数据库造成的损害。

【讨论】:

  • @frlan MySQL doesn't support SELECT ... INTO TABLE.
  • 感谢您的努力,我接受答案。我们的系统管理员意识到了这一点,并且没有授予任何文件权限,而且 PHP 和 MySQL 无论如何都在不同的服务器上运行。顺便说一句,我会再次尝试说服他以正确的方式做事,但我很确定什么都不会改变……我怀疑他暗自为自己的解决方案感到自豪-_-'
猜你喜欢
  • 1970-01-01
  • 2010-09-24
  • 2016-06-01
  • 2012-11-13
  • 2011-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多