【问题标题】:php authentication scriptphp认证脚本
【发布时间】:2009-09-09 18:59:46
【问题描述】:

我需要完成以下身份验证脚本。我在 php/pdo 方面很弱,所以我不知道如何要求行数等于 1,然后从查询结果中设置会话 ID。我不仅需要从结果中设置 $_SESSION['userid'],还需要设置 ['company'] 和 ['security_id'] 。

这是我所拥有的:

$userid   = $_POST['userid'];
$password = $_POST['pass'];
if ( $userid != "" || $password != "" )
{
  $sql = "SELECT * FROM contractors WHERE userid = '" . $userid . "' AND password = '" . $password . "'";
  $result = $dbh->query( $sql );
} else
{
  echo "login failed. Your fingers are too big";
}

可选信息: 浏览器:火狐

【问题讨论】:

  • $query = mysql_query($sql); $result = mysql_fetch_array($query); if ($result['userid'] > 0) { /* 登录 */ }
  • 这不是问题,这是“请为我写一个脚本”...去阅读一些关于 php 身份验证的教程,如果您有任何具体问题,请回到这里...跨度>
  • 当我登录时,我将使用用户名= x';delete from contracts--
  • "可选信息:浏览器:Firefox"
  • 我的 $password="'DROP TABLE 承包商'" :)

标签: php mysql pdo


【解决方案1】:

永远不要使用该代码!

那里有一个非常严重的 SQL 注入。您获取的每个用户输入,无论是来自 cookie、CGI 还是任何地方,都必须在用于 SQL 语句之前进行清理。我可以通过尝试使用如下用户名登录来轻松闯入该系统:

user'; UPDATE contractors SET password = '1337'

... 之后我可以以任何人的身份登录。抱歉,如果我听起来很咄咄逼人,但该代码的作用就像忘记将前门锁在您的公司内,它可能甚至不包含警报系统。

请注意,输入是否真的来自用户并不重要(也许它是在预填充的,隐藏的)。从安全的角度来看,来自外部任何地方的任何东西都必须被视为包含用户的恶意输入。

据我所知,您需要使用 PDO 的 quote 函数来正确清理字符串。 (在 mysql 中,这将通过 mysql_real_escape_string() 完成。)我不是 PDO 方面的专家,请注意,如果我在这里错了,请有人纠正。

另外,您可能不应该将任何密码直接存储在数据库中,而是使用哈希函数创建一个掩码密码,然后从用户提供的密码创建一个哈希,并匹配哈希。您可以使用 PHP hash 函数来执行此操作。

至于其他问题,我不知道您在 SQL SELECT 上的方法是否是最好的方法。我只需选择相应用户的密码并尝试在程序中匹配它。我认为您使用的方法也没有任何错误,但它似乎不合逻辑,因此 me 错过一些错误的可能性更大 - 如果密码和登录名会为漏洞创建一个窗口。

要按照自己的方式进行操作,您需要注意您从PDO query 获得的结果是PDOStatement,这似乎没有可靠的函数来直接计算结果的数量行。您需要使用的是fetchAll,它返回一个行数组,并计算它。然而,正如我所说,这一切对我来说都像是对失败开放,所以我会觉得检查代码中的密码更安全。在这样一个对安全至关重要的地方,与实际密码匹配的距离太远了。

因此,要获取用户 ID 的最终密码,您可以使用 PDOStatement 的 fetch() 从结果中返回列的内容。例如,使用 PDO::FETCH_ASSOC 根据列名将它们放入关联数组中。

解决方法如下:

$userid_dirty   = $_POST['userid'];
$password_dirty = $_POST['pass'];
$success = false; // This is to make it more clear what the result is at the end
if ($userid != "" || $password != "") {
  $userid = $dbh->quote($userid_dirty);
  $passwordhash = hash('sha256',$password_dirty);
  $sql = "SELECT userid, passwordhash, company, security_id FROM contractors WHERE userid = ".$userid;
  $result = $dbh->query( $sql );
  if ($result) { // Check if result not empty, that userid exists
    $result_array = $result->fetch(PDO::FETCH_ASSOC);
    if ($result_array['PASSWORDHASH'] == $passwordhash) {
       // login success
       $success = true;

       // do all the login stuff here...
       // such as saving $result_array['USERID'], $result_array['COMPANY'], $result_array['SECURITY_ID'] etc. 

    } // else fail, wrong password
  } // else fail, no such user
} else {
  // fail, userid or password missing
  echo ' please enter user id and password.';
}
if (!$success) {
  echo ' login failed.';
}

当然,代码可以稍微清理一下,但这应该说明需要做什么。请注意,由于密码都是散列的,并且 从未在 SQL 中使用,因此它实际上不需要清理。但我把它留在那里以防万一,因为在原始代码中它在查询中使用。

请注意,所有有关存储密码的代码都需要更改为存储哈希而不是密码。此外,在散列之前使用添加到密码的salt 是一个非常好的主意。

另外,我提供代码只是为了教育目的 - 我只是认为代码是解释如何做到这一点的最清晰的方式。所以不要把这个网站误认为是请求代码的服务。 :)

【讨论】:

  • 非常感谢 LLari。我真的很感激帮助。我知道该站点不是代码服务。我什至先在另一个站点上发布了代码服务请求,但仍然一无所获。你应该继续justanswer dot com。你可能可以赚到一些好钱。再次表示诚挚的感谢。 $grateful_person = "汤姆";
  • 没问题!我有点想这不是代码请求,但我认为值得一提的是,如果其他读者来阅读这篇文章,以避免误解。而且我明确建议还对这些密码进行加盐处理 (password = hash(plain_password + salt)),因为大多数密码的哈希值可以很容易地用一种叫做 Rainbow Tables 的东西来反转。无论如何,很高兴答案对您有所帮助,并且祝 Tom 编码愉快!
【解决方案2】:

php manual 是学习 PHP 的绝佳资源。看起来你懂一点 SQL,听说过 PDO,这是一个好的开始。如果您在 google 中搜索“PDO”,或者在 PHP 手册中查找该术语,您会找到手册中的 PDO section。看起来你已经找到了->query 函数,所以现在你需要看看它返回了什么。转到该函数的manual page,我们看到它返回一个PDOStatement 对象。 PDOStatement 这个词有助于链接到手册中的相关页面,其中列出了该对象上可用的方法。有一个 rowCount() 方法可能会做你想做的事。

【讨论】:

  • 注意:rowCount()工作。引用文档:“对于大多数数据库,PDOStatement::rowCount() 不会返回受 SELECT 语句影响的行数。”
  • 不感谢吉姆的帮助。我真的等不及 php 手册对我来说不像希腊语那样阅读。
  • @Tom,当您像编写 php 和 sql 那样做“极客”时,希望手册是“极客”。换句话说,man up 和 RTFM。
猜你喜欢
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 2011-08-27
相关资源
最近更新 更多