在过去的几天里,我看到了两个关于 Joomla! 的报告问题,都是无效的。我看到的第一个问题是我们在修复的一个真正的问题。这个问题特别发生在第三方开发者错误地更改我们的表单,注入无效数据时(见我之前的博客文章关于不要篡改核心)。尽管报告者说他们在 1.5.8 中复现了它,但他们提供的示例在我们修复 1.5.8 版本后无法工作。虽然这个错误的“症状”在某些情况下出现,但实际上并没有重新出现。这里的教训是,即使看起来相同,你也需要在整个过程中重新确认错误,然后报告。这也说明了跟进最新版本的重要性,因为我们确实会修复其他问题和安全漏洞。
我看到的另一个问题是“野外 0day 漏洞”。这是我们会特别警觉并立即跟进的电子邮件主题。这个问题的处理方式与我们处理密码重置令牌的方式有关,报告者声称在用户组件的重置部分中,通过令牌输入表单可能存在 SQL 注入的风险。他们提供了复现步骤,还提供了我将在这里引用的解决方案
Proposed fix: In ./components/com_user/controller.php In function confirmreset(): Between the two lines: ---------------------------------------------------------------- $token = JRequest::getVar('token', null, 'post', 'alnum'); // Get the model ---------------------------------------------------------------- This should be changed to: ---------------------------------------------------------------- $token = JRequest::getVar('token', null, 'post', 'alnum'); $token = mysql_real_escape_string($token); // Get the model ----------------------------------------------------------------
正如我们所看到的,报告者认为 JRequest::getVar 需要对输入进行转义(添加 mysql_real_escape_string)。让我们来看看 getVar:这是一个接受五个参数的函数,第四个参数是“变量的返回类型,对于有效值,请参阅JFilterInput::clean()”。在这种情况下,我们选择了 "alnum",这是字母数字过滤器。这个过滤器会剥离任何不是数字或字母的内容,这对于令牌来说很好,因为令牌应该是十六进制的。这也使得 mysql_real_escape_string 变得毫无意义,因为它只是返回字符串本身。但是接下来调用的是重置模型的 "confirmReset" 函数,它接收这个令牌,并有以下代码行
$db->setQuery('SELECT id FROM #__users WHERE block = 0 AND activation = '.$db->Quote($token));
正如我们所看到的,令牌通过数据库类的Quote函数进行处理。如果我们查看这个函数,它接受两个参数,第一个是字符串,第二个是用于切换'转义'文本的开关,默认为true。这样做最终的效果是调用数据库驱动中的"mysql_real_escape_string"函数,这也是报告者最初建议的。顺便提一下,我们尽量避免在这些地方使用"mysql_real_escape_string",因为用户可能实际上并没有运行MySQL,这就是为什么数据库适配器提供字符串转义函数的原因。这样,如果用户确实切换了数据库系统,字符串仍然能够被适当地引用。
所以我们非常欢迎人们报告问题,但在发送给我们之前,请尽量测试并复现问题。在这两种情况下,如果实际尝试一下问题,就会发现问题已经被修复或者不存在。