开发者

md5() function? [duplicate]

This question already exists: Closed 11 years ago.

Possible Duplicate:

Is MD5 really that bad?

Hi,

I'm trying to create a fairly secure log in funct开发者_StackOverflow中文版ion. I use the md5() function to when I insert a user into a MySQL table with SQL and PHP, but the string of letters and numbers that appears in the table of that, isn't that encrypted and a fairly secure way?

Would appreciate some good advice to create a log in function. Thanks!


MD5 is not encryption, it's hashing. A hashing function is not designed to be reversed, but its output is assumed to be relatively unique despite its fixed length so it's a good way to securely store passwords, if you use a cryptographically secure one like SHA-1 or SHA-2 (MD5 is no longer cryptographically secure).


Yes, that's the hash you're seeing. If you're using md5() make sure to at least use a salt. A variable salt for each user would be ideal.

I would also suggest you look into bcrypt. It's much slower than other hash functions and is more secure as well.

Another option is PHP's crypt function.

This SO question has a few answers for and against some hashing/encryption methods. You should check that out as well : How do you use bcrypt for hashing passwords in PHP?

All this will be for naught if you send user passwords over HTTP though. So make sure you have HTTPS and SSL setup as well. And enforce strong passwords! (disclaimer - some people argue against forcing strong passwords because it pisses off users. You will have to decide)


MD5 is a Hash-Function. It works by using a mathematical operation that cannot be easily reversed. It is a good way to store passwords. For the login-check, you simply take to password provided using the login form, apply the MD5 function to this too, and compare the results. A word of warning though: MD5 is not considered secure anymore. Use SHA-1 or others instead.


MD5 hashes are not the best way to hash passwords, it became "broken" (reversed engineered) years ago.

And just hashing a password is not a desirable security level. Using salts, hashing and iterations is. Here's the way I usually create and store a user password:

MySQL table:

create table `users` (
    `id` int unsigned not null auto_increment,
    ...all user properties...
    `salt` varchar(20) not null,
    `pword` blob not null,
    primary key(`id`)
) default charset=utf8 collate utf8_unicode_ci;

Generating a new user and creating a password:

define('SYSTEM_SALT', 'rgcaeg43cg0#3tg_..+g3gg3g'); /* A random system wide salt */
define('ITERATIONS', 1000); /* Number of hashing iterations */
define('KEY_LENGTH', 256); /* Length of the generated hash */

...

$user = new User();

$salt  = PBKDF2::generator(15); /* Salt length is 15 characters */
$pword = PBKDF2::generator(8); /* User password length is 8 characters */

$hashed_pword = PBKDF2::run($pword, SYSTEM_SALT . $salt, ITERATIONS, KEY_LENGTH, PBKDF2::SHA512);

$user->setPassword($hashed_pword);
$user->setSalt($salt);
/* Set the rest of the user properties */

And finally, where the magic happens, the PBKDF2 class implementation:

class PBKDF2 {
    const SHA256 = 'sha256';
    const SHA512 = 'sha512';
    const TIGER  = 'tiger192,4';
    const RIPEMD = 'ripemd256';
    const HAVAL  = 'haval256,5';

    public static function run($password, $salt, $iterations, $key_length, $algorithm) {
        if (!PBKDF2::isAlgorithmAvailable($algorithm))
            throw new PBKDF2Exception("Algorithm not available on your system");

        $key_blocks  = ceil($key_length / strlen(hash($algorithm, null, true)));
        $derived_key = '';

        for ($block = 1; $block <= $key_blocks; $block++) {
            $current = $initial = hash_hmac($algorithm, $salt . pack('N', $block), $password, true);
            for ($i = 1; $i < $iterations; $i++) {
                $current ^= ($initial = hash_hmac($algorithm, $initial, $password, true));
            }

            $derived_key .= $current;
        }

        return substr($derived_key, 0, $key_length);
    }

    public static function isAlgorithmAvailable($algorithm) {
        return in_array($algorithm, hash_algos());
    }

    public static function generator($length = 8) {
        $chars  = 'abcdefghijklmnopqrstuvwxyz0123456789?!_:;,.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?!_:;,.';
        $buffer = '';

        for ($i = 0; $i < intval($length); $i++) {
            $buffer .= $chars[mt_rand(0, strlen($chars) - 1)];
        }

        return $buffer;
    }
}

PBKDF means Password Based Key Derivation Function, and is a part of the PKCS standards. The class above hashes the password 1000 times (you could of course go higher), with the SHA 512 hash implementation in PHP (or your desierable algorithm) and two salts that were merged. This way you should be very secure against rainbow table lookups, which is the standard way of cracking a hashed password.

As you can see I also generate a password for the users, this could of course be non-autogenerated and instead let the users pick their own passwords.


What I believe that has not been explicitly stated at the time of writing this, is that the use of a hashing function has the issue of third parties generating massive indexes of pre-hashed random numbers and letters, or commonly used passwords and names. If your database were every to be breached, most certainly your hashes would be compared to these lookup tables and possibly guessed if they were in there. All they would need is a single lucky match of the administrator's password.

The term for these pre-computed hash lookup tables is generally dubbed "Rainbow tables"

This can be avoided effectively by salting your hashes with a random sequence of characters, therefor each password has something added to it reducing the possibility it has already been pre-computed and indexed in a lookup table. This "salt" can be generated for every user if need be.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜