1

我试过使用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

4 回答 4

0

使用 bcrypt。如果有人拥有您数据库的用户表,那么他们可以使用 brute force/rainbow tables/etc 。即使有盐,破解也只是时间问题。您现在可以说,如果我可以使用 sha-1 进行超过 15k 轮而不是 1k 轮,这有什么意义。使用散列函数进行多次迭代有一些微妙之处,因为必须涉及某种加盐,并且因为现有的散列函数是不像预期的那样随机;所以必须小心,在这种情况下你最终会得到 PBKDF2。bcrypt 优于 PBKDF2-with-SHA-1。其中 bcrypt 源自 Blowfish 分组密码。如果您详细了解情况,您实际上可以看到 bcrypt 比 PBKDF2 更好的一些方面。Bcrypt 是一种密码散列函数,旨在降低速度。准确地说,

SHA512 与 Blowfish 和 Bcrypt

我们希望做的最好的事情是让攻击者和我们的密码散列慢 N 倍。然后我们调整 N 以免超出我们的资源。目标是防止攻击者使用一些非 PC 硬件,这将使他从 bcrypt 隐含的额外工作中受到的影响比我们少。它严重依赖于访问在整个算法执行过程中不断更改的表。这在 PC 上非常快,而在图形处理单元(内存是共享的,所有内核完全控制内部总线)上就更慢了。但有时 bcrypt 并不安全,因此研究人员发明了“scrypt”。所以到处都有一些争议。NIST 人员再次推荐 PBKDF2。但是 PBKDF2 很容易在消费类硬件上被暴力破解。所以如果你真的想要一个安全的系统,

如果您期待 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;
}

}
于 2013-05-23T18:29:08.787 回答
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'))
于 2013-05-23T18:24:44.170 回答
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 漏洞。

于 2013-05-23T18:09:48.483 回答
0

使用 SHA-1 散列密码不会比存储明文更能保护您的密码。问题是,SHA-* 系列的设计速度很快,可以使用普通硬件每秒计算大约3 Giga SHA-1 哈希值。因此,即使您已经编写了一个脚本,现在将其更改为更好的哈希算法,它也永远不会像现在只有 1 个用户那么容易!

PHP 5.5 将有自己的函数 password_hash() 和 password_verify() 准备好,以简化生成 BCrypt 密码哈希。我强烈推荐使用这个优秀的 api,或者它是早期 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);
于 2013-05-23T19:27:07.530 回答