如何将用户输入与散列密码进行比较

时间:2013-05-23 17:59:09

标签: php mysql

我尝试使用sha,但它不起作用,也许我做错了什么。

在数据库密码字段中,我有varchar(65)

如果我键入那么长的“65”它可以登录但是普通密码不是哈希值。

   <?php
require_once '../../../common/server/php/settings.php';



//Connect to users database
$db = mysql_connect('localhost','root','test') or die(mysql_error());
mysql_select_db('test',$db) or die(mysql_error());

//Init request parameters
$userName = (isset($_REQUEST["user_name"])) ? urldecode($_REQUEST["user_name"]) : "";
$password = (isset($_REQUEST["password"])) ? urldecode($_REQUEST["password"]) : "";
$uid = (isset($_REQUEST["uid"])) ? urldecode($_REQUEST["uid"]) : "";
$password = sha1($password);

//Check if user filled login and password in the login screen (Chat authorization)
if($userName != "" && $password != "")
{
  $sql = "SELECT * FROM users WHERE username='".$userName."' AND password='".$password."'";
}
//session/cookie base authorization (Auto login)
else if ($_SESSION['user_id']!="")
{
  $sql = "SELECT * FROM users WHERE id='".$_SESSION["user_id"]."'";
}
// Non session/cookie based autologin authorization
else if ($uid!="")
{
  $sql = "SELECT * FROM users WHERE id='".$_GET['uid']."'";
}
else
{
  echo '<auth error="AUTH_ERROR" />';
  exit;
}

//Select user data
$result = mysql_query($sql,$db);

if(mysql_num_rows($result)==1)
{
  //User found. get user info
  $usersInfo = mysql_fetch_array($result);

  $photo = FLASHCOMS_HTTP_ROOT.'common/images/User1_120.png';
  $photoModeImage = FLASHCOMS_HTTP_ROOT.'common/images/User1_40.png';   

  $answer = '<auth>';
  $answer .= '<userName><![CDATA['.$userName.']]></userName>';
  $answer .= '<gender>male</gender>';
  $answer .= '<age>'.$userInfo['age'].'</age>';
  $answer .= '<level>regular</level>';
  $answer .= '<photo><![CDATA['.$photo.']]></photo>';
  $answer .= '<photoModeImage><![CDATA['.$photoModeImage.']]></photoModeImage>';
  $answer .= '</auth>';
  echo $answer;
  exit;
}
else 
{
  //User not found OR authorization failed
  echo '<auth error="AUTH_ERROR" />';
  exit;
}

?>

登录脚本上的功能

function generateHash($plainText, $salt = null)
    {
        if ($salt === null)
        {
            $salt = substr(md5(uniqid(rand(), true)), 0, 25);
        }
        else
        {
            $salt = substr($salt, 0, 25);
        }

        return $salt . sha1($salt . $plainText);
    }

我忘了告诉我已经登录脚本我想要做的就是将它集成到我的视频聊天中。

4 个答案:

答案 0 :(得分:0)

我建议您使用Bcrypt来进行密码散列。我已经在下面包含了一个我用过的Bcrypt文件 - 可能已经在这里找到了但是我找不到它来引用对不起!!

class Bcrypt {
  private $rounds;
  public function __construct($rounds = 12) {
    if(CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input) {
    $hash = crypt($input, $this->getSalt());

    if(strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash) {
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt() {
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count) {
    $bytes = '';

    if(function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if(strlen($bytes) < $count) {
      $bytes = '';

      if($this->randomState === null) {
        $this->randomState = microtime();
        if(function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input) {
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (1);

    return $output;
  }
}

然后使用它来哈希密码:

$strength = 10;

$bcrypt = new Bcrypt($strength);
$hash = $bcrypt->hash('password'); // This will has your password

$isGood = $bcrypt->verify('password', $hash); // This will verify the password

所以为你完成一个例子:

$password = $_POST['password'];
$username = $_POST['username'];

if(isset($password) && islet($username)){

    $strength = 10;

    $bcrypt = new Bcrypt($strength);
    $hash = $bcrypt->hash('password'); // This will has your password

    $isGood = $bcrypt->verify('password', $hash); // This will verify the password

    if($isGood){

        $sql = "SELECT * FROM users WHERE username='".$userName."' AND password='".$password."'";

    }

}

显然,您需要在“用户名”和“密码”上过滤输入,以删除任何SQL漏洞。

答案 1 :(得分:0)

我可以提供散列密码的替代方法吗?这就是我喜欢的方式,所以我希望这会有所帮助。

在名为 password_salt 用户表格中添加字段。将password和password_salt字段都设置为varchar(40)。创建用户后,将salt设置为$salt = SHA1(microtime());之类的唯一值。您将使用该唯一的盐来散列密码。这样,每个用户哈希都是唯一的,并且无法使用哈希查找表轻松反转。

if($userName != "" && $password != "") {
    $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password=SHA1(CONCAT('%s',password_salt))"),
        mysqli_real_escape_string($userName),
        mysqli_real_escape_string($password),
    );
}

你的盐也可以变得更加漂亮,比如:

password=SHA1(CONCAT(user_id,'%s',password_salt,'secret code'))

答案 2 :(得分:0)

使用bcrypt。如果有人拥有数据库的用户表,那么他们可以使用暴力/彩虹表/等。即使有盐,它也只是时间问题才能被破解。 你现在可以说,如果我可以使用sha-1进行超过15k轮而不是1k轮的话有什么意义。使用哈希函数进行多次迭代有一些细微之处,因为必须有某种类型的salting,并且因为现有的哈希函数是并不像希望的那样随机;所以必须小心,在这种情况下,你最终得到PBKDF2。 bcrypt优于PBKDF2-with-SHA-1。因为bcrypt来自Blowfish分组密码。如果你仔细看一下情况,你实际上可以看到bcrypt优于PBKDF2的一些点。 Bcrypt是一个密码散列函数,旨在减慢速度。确切地说,我们希望密码散列函数尽可能慢 攻击者虽然对​​于诚实的系统没有无法忍受的缓慢。

SHA512 vs. Blowfish and Bcrypt

我们希望做的最好的事情是让攻击者和我们的密码哈希慢N倍。我们然后调整N以便不超过我们的资源。目标是防止攻击者使用一些非PC硬件,这将使他比bcrypt暗示的额外工作受到的影响要小于我们。严重依赖于访问a在整个算法执行过程中不断更改的表。这在PC上非常快,在图形处理单元(内存共享且所有内核完全控制内部总线)上更是如此。但有时候bcrypt并不安全,因此研究人员发明了“scrypt”。所以到处都有一点争议。 NIST的人们再次推荐PBKDF2。但PBKDF2可以很容易地在消费者硬件上强制使用。 因此,如果您确实想要一个安全的系统,请咨询专家并使用git和php.net手册:)

如果您期待scrypt,那么您可以使用此链接: https://github.com/DomBlack/php-scrypt 并为bcrypt:

class SecureHash
{
public function create_hash($password, &$salt = '', $stretch_cost = 10)
{
$salt = strlen($salt) != 21 ? $this->_create_salt() : $salt;
if (function_exists('crypt') && defined('CRYPT_BLOWFISH')) {
return crypt($password, '$2a$' . $stretch_cost . '$' . $salt . '$');
}

if (!function_exists('hash') || !in_array('sha512', hash_algos())) {
throw new Exception('You must have the PHP PECL hash module installed or use PHP 5.1.2+');
}

return $this->_create_hash($password, $salt);
}


public function validate_hash($pass, $hashed_pass, $salt)
{
return $hashed_pass === $this->create_hash($pass, $salt);
}

protected function _create_salt()
{
$salt = $this->_pseudo_rand(128);
return substr(preg_replace('/[^A-Za-z0-9_]/is', '.', base64_encode($salt)), 0, 21);
}

protected function _pseudo_rand($length)
{
if (function_exists('openssl_random_pseudo_bytes')) {
$is_strong = false;
$rand = openssl_random_pseudo_bytes($length, $is_strong);
if ($is_strong === true) return $rand;
}
$rand = '';
$sha = '';
for ($i = 0; $i < $length; $i++) {
$sha = hash('sha256', $sha . mt_rand());
$chr = mt_rand(0, 62);
$rand .= chr(hexdec($sha[$chr] . $sha[$chr + 1]));
}
return $rand;
}

private function _create_hash($password, $salt)
{
$hash = '';
for ($i = 0; $i < 20000; $i++) {
$hash = hash('sha512', $hash . $salt . $password);
}
return $hash;
}

}

答案 3 :(得分:0)

使用SHA-1散列密码不会比保存密码更能保护您的密码。问题是,SHA- *系列设计得很快,可以用普通硬件计算每秒约3 Giga SHA-1 hashes。因此,即使您已经编写了一个脚本,现在将其更改为更好的哈希算法,只需要一个用户就不会像现在这样简单!

PHP 5.5将自己的函数password_hash()和password_verify()准备好,以简化生成BCrypt密码哈希值。我强烈建议使用这个优秀的api,或者它的compatibility pack用于早期的PHP版本。用法非常简单:

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);