2017-02-10 114 views
1

我正在Android上创建一个基本的登录和注册应用程序。无法比较/解密密码(PHP/Android)

我目前面临的问题是我可以加密密码(如图所示),但是当我尝试在我的Android应用程序中登录时,它失败。

我试图做一个非加密的登录,它的工作原理。

我的理论是,PHP文件无法比较或解密密码哈希?

下面的代码和截图。感谢您的时间!

Screenshot of the database

enter image description here


的login.php

<?php 
require("password.php"); 

$con = mysqli_connect("?", "?", "?", "?"); 

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

$statement = mysqli_prepare($con, "SELECT * FROM user WHERE username = ?"); 
mysqli_stmt_bind_param($statement, "s", $username); 
mysqli_stmt_execute($statement); 
mysqli_stmt_store_result($statement); 
mysqli_stmt_bind_result($statement, $colUserID, $colName, $colUsername, $colAge, $colPassword); 

$response = array(); 
$response["success"] = false; 

while(mysqli_stmt_fetch($statement)){ 
    if (password_verify($password, $colPassword)) { 
     $response["success"] = true; 
     $response["name"] = $colName; 
     $response["age"] = $colAge; 
    } 
} 

echo json_encode($response); ?> 

Register.php

<?php 
require("password.php"); 

$connect = mysqli_connect("?", "?", "?", "?"); 

$name = $_POST["name"]; 
$age = $_POST["age"]; 
$username = $_POST["username"]; 
$password = $_POST["password"]; 

function registerUser() { 
    global $connect, $name, $age, $username, $password; 
    $passwordHash = password_hash($password, PASSWORD_DEFAULT); 
    $statement = mysqli_prepare($connect, "INSERT INTO user (name, age, username, password) VALUES (?, ?, ?, ?)"); 
    mysqli_stmt_bind_param($statement, "siss", $name, $age, $username, $passwordHash); 
    mysqli_stmt_execute($statement); 
    mysqli_stmt_close($statement);  
} 

function usernameAvailable() { 
    global $connect, $username; 
    $statement = mysqli_prepare($connect, "SELECT * FROM user WHERE username = ?"); 
    mysqli_stmt_bind_param($statement, "s", $username); 
    mysqli_stmt_execute($statement); 
    mysqli_stmt_store_result($statement); 
    $count = mysqli_stmt_num_rows($statement); 
    mysqli_stmt_close($statement); 
    if ($count < 1){ 
     return true; 
    }else { 
     return false; 
    } 
} 

$response = array(); 
$response["success"] = false; 

if (usernameAvailable()){ 
    registerUser(); 
    $response["success"] = true; 
} 

echo json_encode($response); ?> 

password.php

<?php namespace { 

if (!defined('PASSWORD_BCRYPT')) { 
    /** 
    * PHPUnit Process isolation caches constants, but not function declarations. 
    * So we need to check if the constants are defined separately from 
    * the functions to enable supporting process isolation in userland 
    * code. 
    */ 
    define('PASSWORD_BCRYPT', 1); 
    define('PASSWORD_DEFAULT', PASSWORD_BCRYPT); 
    define('PASSWORD_BCRYPT_DEFAULT_COST', 10); 
} 

if (!function_exists('password_hash')) { 

    /** 
    * Hash the password using the specified algorithm 
    * 
    * @param string $password The password to hash 
    * @param int $algo  The algorithm to use (Defined by PASSWORD_* constants) 
    * @param array $options The options for the algorithm to use 
    * 
    * @return string|false The hashed password, or false on error. 
    */ 
    function password_hash($password, $algo, array $options = array()) { 
     if (!function_exists('crypt')) { 
      trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING); 
      return null; 
     } 
     if (is_null($password) || is_int($password)) { 
      $password = (string) $password; 
     } 
     if (!is_string($password)) { 
      trigger_error("password_hash(): Password must be a string", E_USER_WARNING); 
      return null; 
     } 
     if (!is_int($algo)) { 
      trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING); 
      return null; 
     } 
     $resultLength = 0; 
     switch ($algo) { 
      case PASSWORD_BCRYPT: 
       $cost = PASSWORD_BCRYPT_DEFAULT_COST; 
       if (isset($options['cost'])) { 
        $cost = (int) $options['cost']; 
        if ($cost < 4 || $cost > 31) { 
         trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING); 
         return null; 
        } 
       } 
       // The length of salt to generate 
       $raw_salt_len = 16; 
       // The length required in the final serialization 
       $required_salt_len = 22; 
       $hash_format = sprintf("$2y$%02d$", $cost); 
       // The expected length of the final crypt() output 
       $resultLength = 60; 
       break; 
      default: 
       trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING); 
       return null; 
     } 
     $salt_req_encoding = false; 
     if (isset($options['salt'])) { 
      switch (gettype($options['salt'])) { 
       case 'NULL': 
       case 'boolean': 
       case 'integer': 
       case 'double': 
       case 'string': 
        $salt = (string) $options['salt']; 
        break; 
       case 'object': 
        if (method_exists($options['salt'], '__tostring')) { 
         $salt = (string) $options['salt']; 
         break; 
        } 
       case 'array': 
       case 'resource': 
       default: 
        trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING); 
        return null; 
      } 
      if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) { 
       trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING); 
       return null; 
      } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) { 
       $salt_req_encoding = true; 
      } 
     } else { 
      $buffer = ''; 
      $buffer_valid = false; 
      if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) { 
       $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM); 
       if ($buffer) { 
        $buffer_valid = true; 
       } 
      } 
      if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) { 
       $strong = false; 
       $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong); 
       if ($buffer && $strong) { 
        $buffer_valid = true; 
       } 
      } 
      if (!$buffer_valid && @is_readable('/dev/urandom')) { 
       $file = fopen('/dev/urandom', 'r'); 
       $read = 0; 
       $local_buffer = ''; 
       while ($read < $raw_salt_len) { 
        $local_buffer .= fread($file, $raw_salt_len - $read); 
        $read = PasswordCompat\binary\_strlen($local_buffer); 
       } 
       fclose($file); 
       if ($read >= $raw_salt_len) { 
        $buffer_valid = true; 
       } 
       $buffer = str_pad($buffer, $raw_salt_len, "\0")^str_pad($local_buffer, $raw_salt_len, "\0"); 
      } 
      if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) { 
       $buffer_length = PasswordCompat\binary\_strlen($buffer); 
       for ($i = 0; $i < $raw_salt_len; $i++) { 
        if ($i < $buffer_length) { 
         $buffer[$i] = $buffer[$i]^chr(mt_rand(0, 255)); 
        } else { 
         $buffer .= chr(mt_rand(0, 255)); 
        } 
       } 
      } 
      $salt = $buffer; 
      $salt_req_encoding = true; 
     } 
     if ($salt_req_encoding) { 
      // encode string with the Base64 variant used by crypt 
      $base64_digits = 
       'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/'; 
      $bcrypt64_digits = 
       './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 

      $base64_string = base64_encode($salt); 
      $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits); 
     } 
     $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len); 

     $hash = $hash_format . $salt; 

     $ret = crypt($password, $hash); 

     if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) { 
      return false; 
     } 

     return $ret; 
    } 

    /** 
    * Get information about the password hash. Returns an array of the information 
    * that was used to generate the password hash. 
    * 
    * array(
    * 'algo' => 1, 
    * 'algoName' => 'bcrypt', 
    * 'options' => array(
    *  'cost' => PASSWORD_BCRYPT_DEFAULT_COST, 
    * ), 
    *) 
    * 
    * @param string $hash The password hash to extract info from 
    * 
    * @return array The array of information about the hash. 
    */ 
    function password_get_info($hash) { 
     $return = array(
      'algo' => 0, 
      'algoName' => 'unknown', 
      'options' => array(), 
     ); 
     if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) { 
      $return['algo'] = PASSWORD_BCRYPT; 
      $return['algoName'] = 'bcrypt'; 
      list($cost) = sscanf($hash, "$2y$%d$"); 
      $return['options']['cost'] = $cost; 
     } 
     return $return; 
    } 

    /** 
    * Determine if the password hash needs to be rehashed according to the options provided 
    * 
    * If the answer is true, after validating the password using password_verify, rehash it. 
    * 
    * @param string $hash The hash to test 
    * @param int $algo The algorithm used for new password hashes 
    * @param array $options The options array passed to password_hash 
    * 
    * @return boolean True if the password needs to be rehashed. 
    */ 
    function password_needs_rehash($hash, $algo, array $options = array()) { 
     $info = password_get_info($hash); 
     if ($info['algo'] !== (int) $algo) { 
      return true; 
     } 
     switch ($algo) { 
      case PASSWORD_BCRYPT: 
       $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST; 
       if ($cost !== $info['options']['cost']) { 
        return true; 
       } 
       break; 
     } 
     return false; 
    } 

    /** 
    * Verify a password against a hash using a timing attack resistant approach 
    * 
    * @param string $password The password to verify 
    * @param string $hash  The hash to verify against 
    * 
    * @return boolean If the password matches the hash 
    */ 
    function password_verify($password, $hash) { 
     if (!function_exists('crypt')) { 
      trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING); 
      return false; 
     } 
     $ret = crypt($password, $hash); 
     if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) { 
      return false; 
     } 

     $status = 0; 
     for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) { 
      $status |= (ord($ret[$i])^ord($hash[$i])); 
     } 

     return $status === 0; 
    } 
} } namespace PasswordCompat\binary { 

if (!function_exists('PasswordCompat\\binary\\_strlen')) { 

    /** 
    * Count the number of bytes in a string 
    * 
    * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension. 
    * In this case, strlen() will count the number of *characters* based on the internal encoding. A 
    * sequence of bytes might be regarded as a single multibyte character. 
    * 
    * @param string $binary_string The input string 
    * 
    * @internal 
    * @return int The number of bytes 
    */ 
    function _strlen($binary_string) { 
     if (function_exists('mb_strlen')) { 
      return mb_strlen($binary_string, '8bit'); 
     } 
     return strlen($binary_string); 
    } 

    /** 
    * Get a substring based on byte limits 
    * 
    * @see _strlen() 
    * 
    * @param string $binary_string The input string 
    * @param int $start 
    * @param int $length 
    * 
    * @internal 
    * @return string The substring 
    */ 
    function _substr($binary_string, $start, $length) { 
     if (function_exists('mb_substr')) { 
      return mb_substr($binary_string, $start, $length, '8bit'); 
     } 
     return substr($binary_string, $start, $length); 
    } 

    /** 
    * Check if current PHP version is compatible with the library 
    * 
    * @return boolean the check result 
    */ 
    function check() { 
     static $pass = NULL; 

     if (is_null($pass)) { 
      if (function_exists('crypt')) { 
       $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG'; 
       $test = crypt("password", $hash); 
       $pass = $test == $hash; 
      } else { 
       $pass = false; 
      } 
     } 
     return $pass; 
    } 

}} 
+0

仍在寻找答案。谢谢。 –

回答

1

河豚一般是一个更好的散列算法和下面的代码更容易实现(来源:http://php.net/manual/en/function.crypt.php

<?php 

function password_hash($password, $cost=11){ 
     /* To generate the salt, first generate enough random bytes. Because 
     * base64 returns one character for each 6 bits, the we should generate 
     * at least 22*6/8=16.5 bytes, so we generate 17. Then we get the first 
     * 22 base64 characters 
     */ 
     $salt=substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22); 
     /* As blowfish takes a salt with the alphabet ./A-Za-z0-9 we have to 
     * replace any '+' in the base64 string with '.'. We don't have to do 
     * anything about the '=', as this only occurs when the b64 string is 
     * padded, which is always after the first 22 characters. 
     */ 
     $salt=str_replace("+",".",$salt); 
     /* Next, create a string that will be passed to crypt, containing all 
     * of the settings, separated by dollar signs 
     */ 
     $param='$'.implode('$',array(
       "2y", //select the most secure version of blowfish (>=PHP 5.3.7) 
       str_pad($cost,2,"0",STR_PAD_LEFT), //add the cost in two digits 
       $salt //add the salt 
     )); 

     //now do the actual hashing 
     return crypt($password,$param); 
} 

/* 
* Check the password against a hash generated by the generate_hash 
* function. 
*/ 
function password_verify($password, $hash){ 
     /* Regenerating the with an available hash as the options parameter should 
     * produce the same hash if the same password is passed. 
     */ 
     return crypt($password, $hash)==$hash; 
} 
?> 
+0

此外,你是正确的,“PHP文件无法解密密码哈希”,但我不确定为什么,只是上面的代码对我更好。 – Dan

+0

那么,我该如何正确实施代码呢?我应该用这个代码替换我的password.php吗? @Dan –

+0

是的,只需用Blowfish代码替换整个password.php代码,我也会建议你在Register.php中改变这一行$ passwordHash = password_hash($ password,PASSWORD_DEFAULT);将PASSWORD_DEFAULT更改为rand(),所以它应该如下所示:$ passwordHash = password_hash($ password,rand());这给了password_hash方法一个新的随机起始号码来创建新的哈希值。 – Dan

0

我有同样的问题。 您的原始代码是正确的。

只需将服务器上的密码大小更改为255个字符(实际上它应该是60个字符,建议使用255个字符)。