首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP登录安全性思想

PHP登录安全性思想
EN

Stack Overflow用户
提问于 2012-05-15 01:04:09
回答 3查看 617关注 0票数 0

我有一个系统的想法,以登录用户,并验证他们的登录页面。

我意识到有很多系统,但我主要是好奇我的想法是否好。我做了一些挖掘,但大多数结果似乎遗漏了我一直认为重要的实践(如密码加密等)。我可能会更努力地寻找预制的解决方案,因为它可能更安全,但我没有真正使用过应用程序安全,希望能得到一些反馈。

当用户登录时,他们的姓名和密码将根据数据库进行验证,密码使用SHA256和随机生成的salt进行加密,整个字符串( salt和加密的密码都是128个字符)。long)。下面是密码验证码:

代码语言:javascript
复制
 function ValidatePassword($password, $correctHash)
 {
    $salt = substr($correctHash, 0, 64); //get the salt from the front of the hash
    $validHash = substr($correctHash, 64, 64); //the SHA256

    $testHash = hash("sha256", $salt . $password); //hash the password being tested
    //if the hashes are exactly the same, the password is valid
    return $testHash === $validHash;
}

如果登录有效,则会为其分配一个令牌。此令牌类似于密码加密,但存储加密的纪元以及另一个随机盐。令牌、登录时间、期满时间和用户名被存储在DB中,并且用户名和令牌作为会话信息被发送。

下面是创建令牌的代码:

代码语言:javascript
复制
function loginUser($email)
{
  $thetime = time();
  $ip = $_SERVER['REMOTE_ADDR'];

  $dbuser="///";
  $dbpass="///";
  $dbtable="tokens";
  mysql_connect(localhost,$dbuser,$dbpass);
  mysql_select_db("///") or die( "Unable to select database");

  //Generate a salt
  $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
  //Hash the salt and the current time to get a random token
  $hash = hash("sha256", $salt . $password);
  //Prepend the salt to the hash
  $final = $salt . $hash;

  $exptime = $thetime + 3600;

  //Store this value into the db
  $query = "INSERT INTO `spanel`.`tokens` VALUES ('$final', $thetime, $exptime,    $thetime, '$ip', MD5('$email') )";
  mysql_query($query) or die ("Could not create token.");

  //Store the data into session vars
  $_SESSION['spanel_email'] = $email;
  $_SESSION['spanel_token'] = $final;

  return true;

}

当他们到达一个页面时,他们拥有的令牌和用户名将根据数据库进行检查。如果检查正确,则更新过期时间并加载页面。下面是代码:

代码语言:javascript
复制
function validateUser($page)
{
  //Grab some vars
  $thetime = time();
  $ip = $_SERVER['REMOTE_ADDR'];
  $token = $_SESSION['spanel_token'];
  $email = $_SESSION['spanel_email'];

  $dbuser="///";
  $dbpass="///";
  $dbtable="tokens";
  mysql_connect(localhost,$dbuser,$dbpass);
  mysql_select_db("///") or die( "Unable to select database");

  //Global var
  //Get the var for token expire
  $token_expire = 3600;
  //Validate the token
  $query = "SELECT * FROM `tokens` WHERE `token` LIKE '$token' AND `user_id` LIKE   MD5('$email') AND `exp` > $thetime";
  $result = mysql_query($query) or die(mysql_error());
  //Check if we have a valid result
  if ( mysql_num_rows($result) != 1 ) {
    //Logout the user
    //Destroy the session
    session_destroy();
    //Redirect
    header("location: /spanel/login.php?denied=1");
    exit();
    //(Since the token is already invalid, there's no reason to reset it as invalid)
  }
  $row = mysql_fetch_assoc($result);

  //Update the token with our lastseen
  $newexp = $thetime + $token_expire;
  $query = "UPDATE `spanel`.`tokens` SET `exp` = $newexp, `lastseen_ip` = $thetime,    `lastseen_ip` = '$ip' WHERE `token` LIKE '$token'";
  mysql_query($query);

}

反馈(好的和坏的)是值得欣赏的。就像我说的,我没有做太多的安全工作,希望能得到一些指点。

编辑:我担心我高估了自己创建登录系统的能力。这么说吧,如果你决定停止试图弄清楚混乱的混乱,我可以理解,这可能是有缺陷的想法。

不过,以下是来自登录页面的php代码。(在这里说了这些之后,我意识到仅仅发布密码是一个很大的禁忌)。

代码语言:javascript
复制
    $email = $_POST['email'];
    $password = $_POST['password'];
    $dbuser="///";
    $dbpass="///";
    $dbtable="///";
    mysql_connect(localhost,$dbuser,$dbpass);
    mysql_select_db("spanel") or die( "Unable to select database");
    $query = "SELECT * FROM users WHERE `email` LIKE '$email'";
    $result=mysql_query($query) or die(mysql_error());
    $num=mysql_num_rows($result);
    $row = mysql_fetch_array($result);
    if ( ValidatePassword($password, $row['hash']) == true ) {
      loginUser($email);
      header("location: /spanel/index.php");
    } else {
      echo "<p>Login Failed.</p>";
    }

下面是在创建帐户时生成密码、盐和散列的代码。

代码语言:javascript
复制
 function HashPassword($password)
 {
    $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //get 256 random bits in hex
    $hash = hash("sha256", $salt . $password); //prepend the salt, then hash
    //store the salt and hash in the same string, so only 1 DB column is needed
    $final = $salt . $hash; 
    return $final;
}

感谢你的反馈,我很高兴我缺乏知识的问题是在这里发现的,而不是在攻击之后。

EN

回答 3

Stack Overflow用户

发布于 2012-05-15 01:08:26

首先,这样的散列是不安全的。sha256很容易被破解,至少对于短密码是这样。您必须使用一些hash stretching。看看是否可以找到一些PBKDF2实现,或者使用维基百科对sha256的"for循环“的建议。此外,我不明白使用更多会话变量可以实现什么效果。我不明白validateuser()是做什么的,它仍然依赖于会话id,或者我遗漏了什么。

票数 1
EN

Stack Overflow用户

发布于 2012-05-16 02:53:57

sivann类似,我也看不出增加spanel_token的原因。它所做的一切似乎都是为了确保会话在令牌过期后不再有效。由于WHERE条件的token和user_id的值都存储在会话中,并且仅在登录期间设置,因此它们不会更改。But session expiration can be implemented much easier.

但除此之外,更重要的是:您的代码容易受到SQL注入的攻击。有了你在这里发布的知识,一切都会变得简单。您所需要做的就是执行以下步骤:

  • 在电子邮件中找出使用UNION SELECT注入的用户列数:

‘UNION SELECT null,…,null,其中''=‘

如果输入了错误的列数,脚本将抛出MySQL错误,否则会显示“登录失败”。将会出现。感谢您。使用以下查询执行

000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55被注入到每条记录中,而不是原始的哈希列值。前面的0是盐,其余的字符串是空密码字符串的加盐的SHA-256哈希值,这将产生有效的密码。

‘UNION SELECT t2。* FROM users t1 RIGHT JOIN (SELECT email,'000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55’hash FROM users LIMIT 1) t2 (email) WHERE ''='

这应该足以作为任何用户进行“身份验证”。

票数 1
EN

Stack Overflow用户

发布于 2012-05-15 01:15:12

仅评论一下salt/hash系统:将salt与密码一起存储在数据库中有点违背了salt的目的--如果您的数据库被攻破,那么从安全的角度来看,salt就变得无用了,因为它正好可以帮助猜测/破坏安全性。盐的目的是通过将适当长度的秘密字符串添加到要散列的值中,来增加猜测散列单词的时间。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10587890

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档