不区分大小写的用户名和密码盐

时间:2012-10-03 19:29:59

标签: php passwords case-sensitive salt

我有一个登录系统

例如,Joe可以使用用户名joe登录,而不会出现任何问题。

目前,我使用的是使用用户名作为salt的密码加密。这会产生登录问题。例如,

SELECT * FROM `users` WHERE LOWER(`username`) = LOWER(`:username`)
$stmt->bindValue(':username', $_POST['user']);

这很好用。麻烦涉及密码:

SELECT * FROM `users` WHERE LOWER(`username`) = LOWER(`:username`)
   AND `password` = :password
$stmt->bindValue(':username', $_POST['user']);
$stmt->bindValue(':password', encrypt($_POST['password'], $_POST['user'])); //encrypt(password, salt)

如您所见,密码加密不会检查数据库,因为用户已使用joe而不是Joe

登录

是否有解决方法,或者我应该使用其他东西作为盐?如果是这样,我应该用什么盐?这是我的加密功能:

function encrypt($password, $salt) {
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($salt), $password, MCRYPT_MODE_CBC, md5(md5($salt))));
}

4 个答案:

答案 0 :(得分:2)

首先,使用strtolower($_POST['user'])作为盐有什么问题?看起来它会起作用。

现在一般来说,盐应该是不可预测的。用户名实际上并不是那么不可预测,所以虽然这不会是世界末日,但如果用随机生成的适度长度的字符串替换用户名,用户的安全性会更好(它不需要加密随机,只是不可预测的。)

这里最大的问题是使用MD5 ,一段时间以来一直被认为是不安全的。如果你切换到其他一些哈希函数,安全性会提高; SHA-1并不是一个特别糟糕的选择(它确实具有不良特性:计算速度快),但最适合此类应用的是具有可变加载因子的散列函数,例如bcrypt

答案 1 :(得分:2)

这里有几个问题:

  1. 盐的区分大小写
  2. 您的密码方法"加密"
  3. 第一个问题是你所问的问题,所以让我们来看看。

    因此,您的密码会被用户名腌制,并且您希望能够使用用户在登录时输入的用户名作为盐。如果您确定盐的标准化方案,这将有效。在您的函数中使用它之前,请将其转换为小写或大写,而不是使用它。

    另一个选项是对数据库执行两个查询:一个用于提取存储的用户名,第二个用于实际检查密码。这不是最佳选择,但它确实是你遇到的麻烦。

      

    是否有解决方法,或者我应该使用其他东西作为盐?如果是这样,我应该用什么盐?

    自从您提问后,让我们看看第二个问题:您的密码方法"加密。"

    出于多种原因,尝试发明自己的密码哈希/加密方案绝不是一个好主意。您最好的选择是使用已经广泛接受的密码散列方案,例如bcrypt或PBKDF2的某些衍生产品。这些都很棒,因为它们都包括盐腌和关键拉伸。它们被设计得很慢(相对而言,无论如何),因此强制这些类型的哈希在计算上非常昂贵。

    使用上述密码散列方案之一也可以解决您的第一个问题,因为这些方案使用内置的每用户盐。根据您选择实施这些方案的方式,您不会(不应该)提供自己的盐。顶级库将为您生成盐。

    尝试查看这些库以进行密码哈希:

答案 2 :(得分:1)

跳过SQL lower并使用PHP的strtolower()。这样,您的用户名将全面保持一致。

答案 3 :(得分:1)

您遇到的问题是用户名不应该用作盐的一个原因。哈希密码的更好方法是使用crypt()。你只需要生成一个随机盐来使用它。它返回的字符串包含散列和散列算法,因此您可以根据需要更改算法或难度,而无需重写代码。只要你的哈希是7位安全的,整个字符串就是,所以你不需要base64_encode()任何东西。