Update: This wiki has been rewritten to be in line with Yii 1.1.14. Since many of the detailed complexities are now handled by Yii, the article focuses on how the crypt() built-in function works and why it's important to use it correctly.

There are many tutorials and examples that show storage of passwords in a table.
Often the methods used are substandard and very easy to crack. For example, the
"Agile Web Application Development with Yii1.1 and PHP5"
book's example stores md5($password) in the DB and calls it
"encryption". It is not. "The Yii Blog Tutorial",
(prior to Yii version 1.1.13) was a little better in
that it used a salt but it still used md5 and is easy to crack. (Since 1.1.14 Yii has a
CPasswordHelper class which
the Blog Tutorial uses.)
The yii-user
and yii-user-management extensions
are similarly insecure.
Examples of the same errors abound and are by no means limited to webapps implemented in Yii or PHP.

You cannot rely on a user to use a (practically) unguessable password or to not
use that password in systems other than yours. And you should not assume that
your server is so secure that an attacker cannot get hold of the password file/table or a backup of it.

A very common error I see in what I read and other people's code is fast hashes.
MD5, for example, is very fast. As of Nov
2011 you can check 350 million keys per second on a commodity nVidia processor.
(Update: two years later the technology for brute force password cracking has
advanced to a frightening degree and is moving fast.)
So no matter what you do with salts, the combination of short passwords and fast
brute force checking means your system is open to intruders if you rely on a
non-iterated message digest such as MD5 or any of the SHA algos. Most
hash fuctions are indeed designed to be fast to compute.

The Blowfish hash function is currently considered pretty good. It is designed to be slow. The
implementation in PHP's crypt() is easy to use. Set a cost parameter high enough
to make a brute force attack really slow. I set it so that it takes about 250 ms
on the production server which is fast enough for users to tolerate but slow enough to
defeat a brute-force attack.

Each password should have its own salt. The salt's purpose is to make the
dictionary size in a rainbow table
or dictionary attack so large that the attack is not
feasible. Salts used with the Blowfish hash do not need to be
cryptographically secure
random strings but they do need to be unique. A long enough string from
an operating system's CSPRNG in
non-blocking mode (e.g. /dev/urandom on Linux) is pretty good.

Some people advocate resalting every time a user logs in. I think this is only
useful if you also limit the time interval between user logins, e.g. block an
account if the user hasn't logged in in more than N weeks.

If your software will be in use for many years then you should increase the cost
factor in line with increases in computer speed. You will need to rehash passwords
when do.

People often get confused about how to use implement a password store using crypt().
It is actually very simple but it helps to know that:

It is safe to store the salt together with the password hash. An attacker cannot use
it to make a dictionary attack easier.

The string crypt() returns is the concatenation of the salt you give it and the
hash value.

crypt() ignores excess characters in the input salt string.

crypt() has function signature string crypt (string $str, string $salt) and the
salt string format determines the hash method. For Blowfish hashing, the format is:
"$2a$", a two digit cost parameter, "$", and 22 digits from the alphabet
"./0-9A-Za-z". The cost must be between 04 and 31.

And insert a row into user containing $form->email and $password_hash.

At user logon assume we again have sanitized user input in $form->email and $form->password.
To authenticate these against the accounts in user we select the password_hash field from table user where email = $form->email and, with that value in $password_hash

So there is no need to store the salt in a separate column from the hash value because
crypt() conveniently keeps it in the same string as the hash.

While this example shows how crypt() works, it is too simplistic for practical
use. It glosses over several important
details including: how to obtain a decent salt (the example assumes OpenSSL
is available), what value to use for the cost parameter (the example arbitrarily
uses 13), and what function to use to compare the retrieved database hash value with
the computed value (=== is simple but might be vulnerable to timing attacks).
The APIs in Yii's CSecurityManager and CPasswordHelper are intended to help the
user deal with these matters.

The crypt() function has ben part of PHP for a long time but not all PHP installations
have all its options. The Blowfish hash option is available in all PHP systems since 5.3.
It is also available in older PHPs if either the operating system has the option in
its standard library crypt(3) function
(e.g. many Unix and Linux systems) or if
PHP has the Suhosin patch.

PHP's CRYPT_BLOWFISH constant is true if the system has Blowfish.

I have not found a solution that I can recommend to provide secure password storage
when crypt()'s Blowfish option is absent. If you want to be secure you have to make
this a requirement of your PHP runtime environemnt or take matters into your own
hands.

Some people have commented that phpass has fallback
algorithms when CRYPT_BLOWFISH is false and asked what's wrong with that. They
are not sufficiently secure, in my opinion, to recommend and that's why I don't
recommend phpass.

I do not understand why you continue to make statements about a specialist subject in which, as you have deomonstrated, you have no expertise.

Nevertheles, I have to set the record straight.

"After reading many article on many website. I get a conclusion :"

" Best practice is using using already created library like phpass. phpass is already integrated in wordpress 2.5+, drupal7+, phpbb3+."

" See openwall.org/phpass"

This is not a best practice. It appears to be a common practice. But it is a bad practice.

I recommend against phpass because it implements an iterated MD5 algorithm in PHP and uses it without warning. I explicitly warned against this in the last paragraph of the wiki article.

phpass does this in order to be portable to systems without crypt()'s modular algorithms. But it does so by falling back to insecure behavior. As a result phpass actually creates insecure webapps by giving the programmers that use it the impression that it is secure when it is, in fact, not. On servers that have Blowfish hash, it does nothing more than use crypt() in the way I demonstrated in the article (except that it is implemented in a way to make it hard for the user to understand).

"or you can write your own library."

As I demonstrated in the wiki, the solution is so simple that a library is not needed.

"At this time the computational power required to actually crack a hashed (strong) password doesn't exist."

Wrong! And you contradict this in the following sentences...

"The only way for computers to "crack" a password is to recreate it and simulate the hashing algorithm used to secure it. The speed of the hash is linearly related to its ability to be brute-forced. Worse still, most hash algorithms can be easily parallelized to be reproduced even faster. This is why costly scheme like Bcrypt or Scrypt are so important (google it to know about it)"

I explained the importance of a computationally expensive hash in the wiki. It seems clear now that you have not read it.

"brute forcing a strong password will take long-long time to complete."

How long it takes depends on the entropy of the original password. But you can be sure that it will take an impractically long time if you use Blowfish hash as I demonstrated in the Wiki.

"Salt are make it more harder to crack. But highly still can be cracked."

Wrong again! Salts do not slow down a brute fore attack. The purpose of a salt is to defeat a dictionary (e.g. rainbow) attack.

Some people advocate re-salting every time a user logs in. I think this is only useful if you also limit the time interval between user logins, e.g. by locking out users that have not logged in for a long time.

Could you explain why this would be useful?
In the very unlikely case that someone would succeed in a bruteforce hack of a blowfish encrypted password, they would have the password right? That password would work with any hash based on the same password, no? Maybe I need more coffee though! ;)

phpass will use blowfish if available, password
hashing is a lot more
complicated than just
saying 'no' to 1 hash
function and loosely
hinting that some other
hashing algorithm could
be better, without any
further argumentation.
PHPass is widely
reviewed , created by profesionall with many year of experience (phpass author says : more than 10 year of experience) and found to be
(one of) the best libraries
available for PHP i think.

What i mean with

"At this time the computational
power required to actually crack a
hashed (strong) password doesn't
exist."

is a decode a one way encryption,
one way encrypt cant be decoded it only can be

"the only way for computers to
"crack" a password is to recreate it
and simulate the hashing algorithm used to secure it."

there are available base64 encode / decode, one way encryption/hash (like md5) can only encode, there is no decode

Using salt are make it more harder if the salt is a strong (rare / long / dificult to generate) salt

Good question. Much about security (and not just with computers) depends on time.

How long is the attacker willing to spend on the effort? Your security design is often to make the known attacks take so long that no competent attacker would bother. Both methods described in the wiki work this way. Use a hash that takes half a second to compute rather than half a microsecond slows down the brute-force attack by a factor of a million. Adding 128 bits of entropy to each password makes a dictionary attack 10^38 times harder!

If every password is rehashed at least once a month with a new salt then we make sure that the attacker has only one month to complete the attack, which adds even more confidence. To rehash, you need to have the password cleartext so you do it when a user logs in. But if the user doesn't log in then that starts to defeat the purpose. Hence my comment that to make the trick work, you need limit how long an account can be unused and still be accessed with the old password.

"password hashing is a lot more complicated than just saying 'no' to 1 hash function and loosely hinting that some other hashing algorithm could be better, without any further argumentation."

I do not agree that password hashing is complicated in PHP. Not at all. Any decent PHP programmer can handle it.

My recocomendation is that people use crypt() with the Blowfish hash option and not use a server without it for secure password storage. Again, not complicated.

"PHPass is widely reviewed , created by profesionall with many year of experience (phpass author says : more than 10 year of experience) and found to be (one of) the best libraries available for PHP i think."

If these claims give you confidnce in the library then you must be easily persuaded. I recommend that people take the trouble to understand the security aspects of the software for which they are responsible. This is why I try to be completely transparent and why I explained in the wiki every detail of how the software I recommend works.

This is a good opportunity to point out that this is not the only Openwall recommendation that I think is dangerous. And phpass is not the only PHP security lib I have reviewed that is dangerously flawed.

The extension integrates phpass into Yii in simply no-time.
I see little reason in reinventing the wheel. Also, for those who wish NOT to have their passwords security reduced its recommended to stay with hashPortable = false in the configuration (just as stated by the author...).

In any case - its good that this subject is being discussed. For some strange reason many developers are still ignorant with regard to this basic security issue.

There are a number of reasons why I recommend against using phpass, some already discussed in these comments. Others include its complexity, the inclusion of 6 hash algorithms that are better avoided (some of which are known to be unsafe), the inclusion of unproven password strength heuristics, and the lack of care regarding timing attacks.

@Boaz: This wiki does not reinvent a wheel, it attempts to educate the reader in correct use of crypt(), which is not what phpass does.

I understand the desire for a simple solution that "just works" in "simply no-time". But phpass is not a good choice. password_compat is the best I can identify.

it attempts to educate the reader in correct use of crypt(), which is not what phpass does.

And this is good. Still, my point is that I think that the reader should also consider using phpass which is IMHO a very good off-the-shelf solution for password encryption/checking, if you know how to use it (this means knowing the territory, familiarize oneself with its limitations and configuring it accordingly).
I'm not an expert on security and most programmers should not be experts on that subject as well. But nor should they refrain from investing themselves in that subject when appropriate.
The conclusion I came to when I invested myself into the issue a while back was that probably phpass is the best solution for me. A maintained library for password generation/check that is robust enough and safe enough, that someone has already thought of for me (among the rest :-) .
I also suggest that if you have feedback on phpass you should submit it to the maintainers of this library/package.

yii-password-strategies has some nice features—upgrading the cost parameter at login is nice. The password entropy policy checks are a useful example but applications generally need a password policy derived from system requirements.

On the down side, yii-password-strategies incorporates 4 hashing methods, 3 of which are insecure and should not be used. And it's implementation of all 4 is potentially open to timing attacks owing to the string comparison function.

Versions of PHP before 5.3.7 only support "$2a$" as the salt prefix: PHP 5.3.7 introduced the new prefixes to fix a security weakness in the Blowfish implementation. Please refer to » this document for full details of the security fix, but to summarise, developers targeting only PHP 5.3.7 and later should use "$2y$" in preference to "$2a$".

which generates a string longer than 22 characters, but now the crypt function works. Can I use bin2hex confidently? Is it still a random number considering the fact that crypt will truncate only the first 22 characters of the salt?