【问题标题】:Is this vulnerable to SQL injection这是否容易受到 SQL 注入的影响
【发布时间】:2011-10-22 06:38:35
【问题描述】:

我意识到已经有很多关于此的问题。但是我的方法和他们的不一样,所以我想知道。我想我了解 SQL,但我不想冒险在未来犯错,所以感谢您的帮助。 (这只是我正在做的一个项目,不是家庭作业或任何重要的事情)。

function checkLogin($username, $password) {
    $username = strtolower($username);
    connectToDatabase();
    $result = mysql_query("SELECT * FROM `users` WHERE username='$username'");
    $dbpassword = "";
while($row = mysql_fetch_array($result))
  {
    $rowuser = $row['username'];
  if($username != $row['username']) continue;
  $dbpassword = $row['password'];
  }
    if($dbpassword == "") {
        return false;
    }
    $genpass = generatePassword($password);
   return $genpass == $dbpassword;
}

所以用你最好的一击打我:) 而且我不认为我的方法尽可能有效。不幸的是,我对 php 的理解不够了解 $row = mysql_fetch_array($result) 正在做什么。

【问题讨论】:

  • SQL 注入是在为您的函数提供 $username 或 $password 的奇怪值时出现的。如果这些值来自外部提供的来源,那么您就有麻烦了。
  • @Ira Baxter,它来自 POST,所以我猜这意味着我遇到了麻烦?
  • 考虑到有人可能会为用户名输入文本“' OR 'A=A”。然后你的循环会尝试所有用户的密码,我想。这将使猜测密码变得更容易。如果您的 SQL 允许在查询调用中使用多个语句,则用户名文本可能是 "'; DELETE * FROM 'users' 这将清除您的用户表,或者将某些用户的密码设置为特定密码的 UPDATE 语句,使使用该密码登录很简单。您需要检查的是检查用户名字符串是否包含引号。
  • 我在这里为每个答案 +1。任何登陆此页面的人:使用准备好的语句没有缺点。并且您可以轻松入睡。

标签: php sql code-injection


【解决方案1】:

因为您正在获取任意字符串并将其直接放入 SQL 语句中,所以您很容易受到 SQL 注入的攻击。

已编辑基于下面的评论。)

SQL 注入的经典示例是创建如下用户名:

Robert'); DROP TABLE users;--

Obligatory XKCD link

解释:

鉴于上面的“用户名”,插入到您的字符串会导致:

SELECT * FROM `users` WHERE username='Robert'); DROP TABLE users;--'

最后的注释符号-- 是“摆脱”你的结束引号所必需的,因为我只是用我的一个替换了我的一个来结束你的选择语句,这样我就可以注入一个 DROP TABLE 语句。

正如@sarnold 指出的那样,PHP 的mysql_query 只执行字符串中的第一个查询,因此上面的示例(称为query stacking)不适用。函数在这里解释:http://php.net/manual/en/function.mysql-query.php

可以在here 找到更好的示例。这里他们使用的用户名是

' OR 1 OR username = '

内插成为

SELECT * FROM `users` WHERE username='' OR 1 OR username = ''

这会导致您的应用程序检索所有用户。

【讨论】:

  • 我刚试过这个,它并没有丢掉我的桌子,为什么会这样?
  • 那个字符串不是一个很好的例子;默认情况下,mysql_queryonly executes the first query in the string。让 PHP 尝试使用 hacky 机制解决安全问题。 咳嗽魔术引号咳嗽
  • 感谢萨诺德。我不知道! +1
【解决方案2】:

简短的回答是肯定的。

一个或许更有帮助的答案是,您永远不应该相信用户输入;如果您有可用的 PDO,准备好的语句是防止这种情况发生的最简单方法。见PDO Prepared Statements

<?php
$stmt = $dbh->prepare("SELECT * FROM `users` WHERE username=?");
if ($stmt->execute($username)) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}
?>

【讨论】:

    【解决方案3】:

    其他答案很好地描述了您的问题,但是,我认为它们都忽略了最佳解决方案:使用 PHP 的 PDO Prepared Statements 进行查询。

    $stmt = $dbh->prepare("SELECT * FROM users where username = ?");
    if ($stmt->execute(array($username))) {
      while ($row = $stmt->fetch()) {
        print_r($row);
      }
    }
    

    这是一个小而简单的例子。有更复杂的使用 PDO 的方法可能更适合您的应用程序。

    当您使用 PDO 准备语句时,您永远不需要手动转义任何内容,只要您使用这种略有不同的风格,您就永远不会编写 SQL 注入漏洞并且您不必维护每个基础“数据”有两个变量——一个已清理,一个是用户提供的——因为只需要一个。

    【讨论】:

      【解决方案4】:

      我会说是的,它对 SQL 注入开放。

      这是因为您以 $username 的形式获取用户输入并将其放入您的 SQL 语句中,而没有确保它是干净的。

      这是我喜欢在我的应用程序中使用的用于清理字符串的函数:

      function escape($data) {
          $magicQuotes = get_magic_quotes_gpc();
      
          if(function_exists('mysql_real_escape_string')) {
              if($magicQuotes) {
                  $data = stripslashes($data);
              }
      
              $data = mysql_real_escape_string($data);
          }
          else {
              if(!$magicQuotes) {
                  $data = addslashes($data);
              }
          }
      
          return $data;
      }
      

      那么你可以这样使用它:

      $username = escape(strtolower($username));
      connectToDatabase();
      $result = mysql_query("SELECT * FROM `users` WHERE username='$username'");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-02
        • 2012-11-16
        • 1970-01-01
        • 1970-01-01
        • 2016-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多