【问题标题】:Is this PHP/MySQL statement vulnerable to SQL injection?这个 PHP/MySQL 语句是否容易受到 SQL 注入的影响?
【发布时间】:2009-07-18 01:21:22
【问题描述】:

应该是一个简单的问题,我只是不熟悉 PHP 语法,我想知道以下代码是否可以免受 SQL 注入攻击?:

private function _getAllIngredients($animal = null, $type = null) {
    $ingredients = null;
    if($animal != null && $type != null) {
        $query = 'SELECT id, name, brief_description, description, 
                         food_type, ingredient_type, image, price,
                         created_on, updated_on
                    FROM ingredient
                   WHERE food_type = \'' . $animal . '\'
                     AND ingredient_type =\'' . $type . '\';';
        $rows = $this->query($query);

        if(count($rows) > 0) {

等等等等等等

我搜索了一下,似乎注射安全代码看起来与 WHERE food_type = \'' 不同。 $动物。 '\' 在这里使用的语法。

抱歉,我不知道这里使用的是什么版本的 PHP 或 MySQL,或者是否正在使用任何 3rd 方库,任何有专业知识的人都可以提供任何意见吗?

更新

\在语句中的作用是什么?:

WHERE food_type = \'' . $animal . '\'  

在我的谷歌搜索中,我发现了很多对 mysql_real_escape_string 的引用...这是防止 SQL 注入和其他恶意行为的功能吗?

类声明是:

class DCIngredient extends SSDataController

那么可以想象mysql_real_escape_string 包含在其中吗?
我应该要求查看 SDataController 的实现吗?

【问题讨论】:

  • \ 转义了 ' 以便它不会终止字符串。如果您键入 'food_type = '' . $animal . ''' 会产生错误。另一种写法是"food_type = '".$animal."'" 使用双引号。但是你应该知道双引号也会解析字符串中的变量,而单引号则不会。
  • 在回答你的第三个问题时,mysql_real_escape_string 确实转义了字符串以防止 SQL 注入,但你也应该使用准备好的语句。
  • LastName = 'O'Reilley' 怎么样?是转义处理内联单引号吗?这是它的目的吗?

标签: php mysql sql-injection


【解决方案1】:

是此代码易受 SQL 注入攻击。

“\”只转义引号字符,否则 PHP 认为引号将结束您的 (sql-) 字符串。

此外,当您将整个 SQL 字符串传递给 SSDataControler 类时,如果已注入准备好的字符串,则无法再避免攻击。

所以SSDataControler 类被设计破坏(易受攻击)。

试试这样更安全的方法:

$db_connection = new mysqli("host", "user", "pass", "db");
$statement = $db_connection->prepare("SELECT id, name, brief_description, description, 
                     food_type, ingredient_type, image, price,
                     created_on, updated_on
                FROM ingredient
               WHERE food_type = ?
                 AND ingredient_type = ?;';");
$statement->bind_param("s", $animal);
$statement->bind_param("s", $type);
$statement->execute();

通过使用 bind 方法,您可以指定参数的类型(s 表示字符串,i 表示整数等),您将永远不会再考虑 sql 注入

【讨论】:

    【解决方案2】:

    你也可以使用 mysql_real_escape_string 来摆脱任何可以做删除表的事情,或者执行任何其他任意代码。

    无论您在 SQL 语句中的哪个位置放置值,它都可以有一个 ';'在其中,它立即结束语句并开始一个新语句,这意味着黑客几乎可以为所欲为。

    为了安全起见,只需将您的值包装在 mysql_real_escape_string($variable) 中。所以:

    WHERE Something='".mysql_real_escape_string($variable)."'
    

    【讨论】:

      【解决方案3】:

      $animal 可以是一个包含'; drop table blah; -- 的字符串,所以是的,这对 SQL 注入很脆弱。

      您应该考虑使用准备好的语句,在其中绑定参数,这样就不会发生注入:

      http://us3.php.net/pdo.prepared-statements

      【讨论】:

        【解决方案4】:

        它很脆弱。如果我通过了:'\'; DROP TABLE 成分;选择 \'' 作为 $type,噗,再见成分表。

        【讨论】:

          【解决方案5】:

          如果它是一个私有函数,有点。如果您担心可以访问源代码注入 SQL 的人,有更简单的方法可以实现他们的目标。为了安全起见,我建议在使用前将参数传递给mysql_real_escape_string()。像这样:

          private function _getAllIngredients($animal = null, $type = null) {
                  $animal = mysql_real_escape_string($animal);
                  $type   = mysql_real_escape_string($type);
                  ...
                  }
          

          为了更加安全,您甚至可以使用 ENT_QUOTES 标志将其传递给 htmlentities() - 这也有助于防止 XSS 类型的东西,除非您将这些数据库条目的内容放入 @987654326 @标签。

          但您可以做的最安全的事情是编写自己的清理函数,这将充分利用各种技术,还可以让您轻松防御未来可能出现的新威胁。

          【讨论】:

          【解决方案6】:

          回复:更新

          \'' 用于将变量括在引号中,这样当它通过 SQL 时,空格不会破坏任何内容。 IE:Something=Cold Turkey 会以错误结尾,而 Something='Cold Turkey' 不会。

          此外,类扩展不会影响您如何组合 MySQL 语句。

          【讨论】:

          • 对,但他们可能不会在 $this->query() 中调用 mysql_real_escape_string 吗?
          • 你不能这样做,因为那样它会转义所有 MYSQL 使用的有意字符。
          • 之所以存在转义是为了摆脱来自外部来源的“无意”MySQL 字符。不要去掉有意的分号、引号等。他们“可能”在 $this->query(); 中调用它,但它是不安全的,因为该函数很像 MySQL,可能无法弄清楚什么是值,什么是命令。
          【解决方案7】:

          如果用户或任何第 3 方无论如何都向您的系统注入了 $animal 的值(他们可能会这样做),那么是的,它对 sql 注入很不利。

          解决这个问题的方法是这样做

          private function _getAllIngredients($animal = null, $type = null) {
              $ingredients = null;
              if($animal != null && $type != null) {
                  $query = 'SELECT id, name, brief_description, description, 
                                   food_type, ingredient_type, image, price,
                                   created_on, updated_on
                              FROM ingredient
                  $rows = $this->query($query);
                  if(count($rows) > 0) {
                  if($rows['animal'] == $animal && $rows['ingredient_type'] == $type) {
          

          注意:我从 sql 中删除了 WHERE 语句,并将 if 语句添加到循环中

          【讨论】:

          • 这段代码是否不会从本质上提取整个表格,然后然后应用标准?
          • 是的,它会更慢,但你可以绝对确定你不会被注入 sql
          • 好的,恕我直言,我认为您应该阅读一些针对此问题的其他出色答案。
          • 是的,我同意,我实际上花了最后一个小时看着它们。 (特别是mysqli准备好的语句),但是,这是在之前这些答案发布的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-03-02
          • 2016-03-29
          • 1970-01-01
          • 2012-11-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多