I wonder if Facebook stores it's password in clear-text, since you can login with either 'Password' or 'password', does it hash the first character and the rest into 2 different hashes? If not, we have a our passwords in readable form in their database that have huge privacy and security issues.
They hash it once and save it to the database. When logging in, they generate three hashes (if I remember correctly) and compare it to the hash in the database. If any match, it logs you in.
You seemingly don't understand a bit about it. And you seemingly doesn't understand how crypt works. Let me educate you:
1. When user registers, his password is hashed with that hash-function, and that hash is stored in a database (it uses random salt).
2. When user tries to access the site, a password is hashed against the hash stored in a database, and it should return same hash if matched (this is how crypt works!).
3. In non strict mode we try also two different passwords to match the hashes (just like Facebook does).
Code example:
1. $hash = \password\hash('user entered password'); // store it to db
Isn't that supposed to increase the chances of guessing the password? Unless there's a constraint on the number of attempts to guess the password, which I think there is.
It's more likely that they coerce to lowercase the the first letter of the password you put in and then store/compare the hash of that resulting plaintext. They could even transparently upgrade passwords created before they started doing this by using the plaintext from the next time you login successfully to regenerate the hash.
Lowercasing the first character--by itself alone--does not address inverted case scenario (e.g. "PaSsWoRd" and "pAsSwOrD" evaluate to "paSsWoRd" and "pAsSwOrD" respectively).
One way to resolve that issue is to create two versions of the password (one with normal casing and one with inverted casing, but both with the first character lowercased), sort them, and pick the first result.
["pAsSwOrD", "PaSsWoRd", "PAsSwOrD"].map(function canonicalize(pwd) {
function invert(str) {
return (str == str.toUpperCase()
? str.toLowerCase()
: str.toUpperCase());
}
var head = pwd.substring(0, 1).toLowerCase();
var tail = pwd.substring(1);
var vers = [head + tail,
head + tail.split("").map(invert).join("")];
return vers.sort()[0];
});
Which gives the following result:
["pAsSwOrD", "pAsSwOrD", "pAsSwOrD"]
The three different variations get canonicalized into one version. With it, you can just store one hash instead of three.