将光标移到/点击文章中的句子上,可以查看译文。      显示繁体中文内容    显示简体中文内容

Secure hash and salt for PHP passwords
PHP密码的安全哈希和salt

It is currently said that MD5 is partially unsafe.Taking this into consideration, i'd like to know which mechanism to use for password protection.

This question, is"double hashing"a password less secure than just hashing it once?suggests that hashing multiple times may be a good idea, whereas how to implement password protection for individual files?suggests using salt.

I'm using PHP. i want a safe and fast password encryption system.Hashing a password a million times may be safer, but also slower.how to achieve a good balance between speed and safety?Also, i'd prefer the result to have a constant number of characters.

  1. The hashing mechanism must be available in PHP
  2. It must be safe
  3. It can use salt (in this case, are all salts equally good?is there any way to generate good salts? )

Also, should i store two fields in the database (one using MD5 and another one using SHA, for example)?would it make it safer or unsafer?

In case i wasn't clear enough, i want to know which hashing function to use and how to pick a good salt in order to have a safe and fast password protection mechanism.

Related questions that don't quite cover my question :

what's the difference between SHA and MD5 in PHP
Simple Password Encryption
Secure methods of storing keys, passwords for asp.net
how would you implement salted passwords in Tomcat 5.5

时间:

A much shorter and safer answer - don't write your own password mechanism at all, use one that is tried and tested, and incorporated into WordPress, Drupal etc, i.e. Openwall's phpass.

Most programmers just don't have the expertise to write crypto related code safely without introducing vulnerabilities.

Quick self-test : what is password stretching and how many iterations should you use?if you don't know the answer, you should use phpass, as password stretching is now a critical feature of password mechanisms due to much faster CPUs and the use of GPUs and FPGAs to crack passwords at rates of billions of guesses per second (with GPUs).

For example, you can now crack all 8 -character Windows passwords in 6 hours using 5 commodity desktop PCs with 5 GPUs per PC.this is brute-forcing i.e. enumerating and checking every 8 -character Windows password, including special characters, and is not a dictionary attack.there are also many rainbow table attacks which run on ordinary CPUs and are very fast.all this is because Windows still doesn't salt or stretch its passwords - don't make the same mistake as Microsoft did!

See this excellent answer for more about why phpass is the best way to go.

I just want to point out that PHP 5.5 includes a password hashing API that provides a wrapper around crypt().this API significantly simplifies the task of hashing, verifying and rehashing password hashes.the author has also released a compatibility pack (in the form of a single password.php file that you simply require to use), for those using PHP 5.3.7 and later and want to use this right now.

It only supports BCRYPT for now, but it aims to be easily extended to include other password hashing techniques and because the technique and cost is stored as part of the hash, changes to your prefered hashing technique/cost will not invalidate current hashes, the framework will automagically, use the correct technique/cost when validating.it also handles generating a"secure"salt if you do not explicitly define your own.

The API exposes four functions :

  • password_get_info() - returns information about the given hash
  • password_hash() - creates a password hash
  • password_needs_rehash() - checks if the given hash matches the given options.useful to check if the hash conforms to your current technique/cost scheme allowing you to rehash if necessary
  • password_verify() - verifies that a password matches a hash

At the moment these functions accept the PASSWORD_BCRYPT and PASSWORD_DEFAULT password constants, which are synonymous at the moment, the difference being that PASSWORD_DEFAULT"may change in newer PHP releases when newer, stronger hashing algorithms are supported."using PASSWORD_DEFAULT and password_needs_rehash() on login (and rehashing if necessary) should ensure that your hashes are reasonably resilient to brute-force attacks with little to no work for you.

EDIT : i just realised that this is mentioned briefly in Robert K's answer.i'll leave this answer here since i think it provides a bit more information about how it works and the ease of use it provides for those who don't know security.

I'm using Phpass which is a simple one-file PHP class that could be implemented very easily in nearly every PHP project.see also the H.

By default it used strongest available encryption that is implemented in Phpass, which is bcrypt and falls back to other encryptions down to MD5 to provide backward compatibility to frameworks like Wordpress.

The returned hash could be stored in database as it is.Sample use for generating hash is :


$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

To verify password, one can use :


$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

THINGS to REMEMBER

A lot has been said about Password encryption for PHP, most of which is very good advice, but before you even start the process of using PHP for password encryption make sure you have the following implemented or ready to be implemented.

SERVER

PORTS

No matter how good your encryption is if you don't properly secure the server that runs the PHP and DB all your efforts are worthless.most servers function relatively the same way, they have ports assigned to allow you to access them remotely either through ftp or shell.Make sure that you change the default port of which ever remote connection you have active.by not doing this you in effect have made the attacker do one less step in accessing your system.

USERNAME

For all that is good in the world do not use the username admin, root or something similar.also if you are on a unix based system do not make the root account login accessible, it should always be sudo only.

PASSWORD

You tell your users to make good passwords to avoid getting hacked, do the same.what is the point in going through all the effort of locking your front door when you have the backdoor wide open.

DATABASE

SERVER

Ideally you want your DB and APPLICATION on separate servers.this is not always possible due to cost, but it does allow for some safety as the attacker will have to go through two steps to fully access the system.

USER

Always have your application have its own account to access the DB, and only give it the privileges it will need.

Then have a separate user account for you that is not stored anywhere on the server, not even in the application.

Like always do not make this root or something similar.

PASSWORD

Follow the same guidelines as with all good passwords.also don't reuse the same password on any SERVER or DB accounts on the same system.

PHP

PASSWORD

NEVER ever store a password in your DB, instead store the hash and unique salt, i will explain why later.

HASHING

ONE way HASHING!!!!!!!, never hash a password in a way that it can be reversed, Hashes should be one way, meaning you don't reverse them and compare them to the password, you instead hash the entered password the same way and compare the two hashes.this means that even if an attacker gets access to the DB he doesn't know what the actually password is, just its resulting hash.which means more security for your users in the worst possible scenario.

There are a lot of good hashing functions out there ( password_hash, hash, etc...) but you need to select a good algorithm for the hash to be effective.(bcrypt and ones similar to it are decent algorithms. )

When hashing speed is the key, the slower the more resistant to Brute Force attacks.

One of the most common mistakes in hashing is that hashes are not unique to the users.this is mainly because salts are not uniquely generated.

SALTING

Passwords should always be salted before hashed.Salting adds a random string to the password so similar passwords don't appear the same in the DB.however if the salt is not unique to each user (ie :you use a hard coded salt) than you pretty much have made your salt worthless.because once an attacker figures out one password salt he has the salt for all of them.

When you create a salt make sure it is unique to the password it is salting, then store both the completed hash and salt in your DB.what this will do is make it so that an attacker will have to individually crack each salt and hash before they can gain access.this means a lot more work and time for the attacker.

USERS CREATING PASSWORDS

If the user is creating a password through the frontend that means it has to be sent to the server.this opens up a security issue because that means the unencrypted password is being sent to the server and if a attacker is able to listen and access that all your security in PHP is worthless.always transmit the data SECURELY, this is done through SSL, but be weary even SSL is not flawless (OpenSSL's Heartbleed flaw is an example of this).

Also make the user create a secure password, it is simple and should always be done, the user will be grateful for it in the end.

Finally, no matter the security measures you take nothing is 100% secure, the more advanced the technology to protect becomes the more advanced the attacks become.but following these steps will make your site more secure and far less desirable for attackers to go after.

Here is a PHP class that creates a hash and salt for a password easily

http://git.io/mSJqpw

As of PHP 5.5, PHP has simple, secure functions for hashing and verifying passwords, password_hash() and password_verify()


$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash);//Returns true
password_verify('anna', $expensiveHash);//Also returns true
password_verify('elsa', $hash);//Returns false

When password_hash() is used, it generates a random salt and includes it in the outputted hash (along with the the cost and algorithm used.) password_verify() then reads that hash and determines the salt and encryption method use, and verifies it against the provided plaintext password.

Providing the PASSWORD_DEFAULT instructs PHP to use the default hashing algorithm of the installed version of PHP.exactly which algorithm that means is intended to change over time in future versions, so that it will always be one of the strongest available algorithms.

Increasing cost (which defaults to 10 ) makes the hash harder to brute-force but also means generating hashes and verifying passwords against them will be more work for your server's CPU.

Note that even though the default hashing algorithm may change, old hashes will continue to verify just fine because the algorithm used is stored in the hash and password_verify() picks up on it.

...