I am having problems login users in using the below code.
It seems like when I execute my if statement with the correct user password the password entered by the user and the password in my database are not matching up. Can someone give me their input on what I am doing wrong?
$pwd = hashed password in my database
$pass = password users enter on logi page
if ($pwd === PwdHash($pass,substr($pwd,0,9))) {
function PwdHash($pwd, $salt = null)
{
if ($salt === null) {
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else {
$salt = substr($salt, 0, SALT_LENGTH);
}
return $salt . sha1($pwd . $salt);
}
Can someone give me their input on what I am doing wrong?
Not to offend you, but you're literally doing everything wrong. Let's start right at the beginning:
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
This is a very poor way to calculate a salt. Right from the rand man page:
This function does not generate cryptographically secure values, and should not be used for cryptographic purposes.
Right there alone, your whole mechanism falls apart. Security is only as good as its weakest component. But it doesn't stop there. uniqid() creates a unique id, however the main problem with this is that it is based on the current time. Having a unique salt is good, but since it is strictly time-based, it makes it predictable, which is very bad and far outweighs the benefits of having it unique.
Next, you md5 the salt. This adds absolutely nothing in terms of security and it could possibly be debated that it actually reduces security due to md5 collisions.
Now on to how you're hashing your password:
$salt . sha1($pwd . $salt);
Sha1 is very fast, and is therefore a very bad choice for password hashing. Doing salt . fastHash(password . salt) is simply security by obscurity and is not security at all.
So what should you be doing?
First step: STOP rolling your own password hashing mechanism and leave it in the hands of experts who are smarter than you and I.
Second step: Use password_hash. If you don't have PHP 5.5 check the comments on that page for a compatibility library compatible with earlier versions. It's as simple as doing:
$hash = password_hash("someAmazingPassword", PASSWORD_DEFAULT);
Then see password_verify() for verifying the hashes.
You should put SALT_LENGTH to your checking function as you do in your generator function. .
Manually cheking are they different or the same?
Related
I'm trying to make register and log in forms having salt encryption, and I'm not really familiar with it. So everything is working except that log in can't recognize password so I'm pretty sure it's encryption problem. These are lines for register:
$hash = hash('sha256', $password1);
function createSalt()
{
$text = md5(uniqid(rand(), true));
return substr($text, 0, 3);
}
$salt = createSalt();
$password = hash('sha256', $salt . $hash);
and these are for login:
$userData = mysql_fetch_array($result, MYSQL_ASSOC);
$hash = hash('sha256', $userData['salt'] . hash('sha256', $password) );
if($hash != $userData['password'])
{
echo "Incorrect password";
}
Can anybody point the problem. Thanks!
Actually your code should work as far as i can see, though it is very unsafe!
Problem: SHA256 is not appropriate to hash passwords, because it is ways too fast. Use a slow key-derivation function like BCrypt.
Problem: A three character salt with only letters is nearly no protection.
Maybe your database field is smaller than 64 characters, or you are comparing different passwords. In every case there is an easier and safer way to hash passwords, just use the new functions password_hash() and password_verify(). There exists also a compatibility pack for earlier PHP versions.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
There are quite a few things wrong with this. For starters: Are you storing the salt with the password? If not, then passwords become unverifiable.
Security considerations:
hash('sha256', ... is insufficient; consider bcrypt, scrypt, or pbkdf2
https://github.com/DomBlack/php-scrypt
http://us2.php.net/password_hash
https://defuse.ca/php-pbkdf2.htm
$text = md5(uniqid(rand(), true)); Ever heard of openssl_random_pseudo_bytes()?
(Also, you shouldn't seek to decrypt passwords, only verify them.)
If you're not familiar with these concepts, play it safe and use a tried and true library.
I'm upgrading my auth class, replacing md5 with crypt for storing passwords. Here's the approach I've taken:
function crypt_pass($pass, $userID) {
$salt = $userID .'usesomesillystringforsalt'; // min 22 alphanumerics, dynamic
$method = (version_compare('5.3.7',PHP_VERSION,'>=')) ? '2y' : '2a'; // PHP 5.3.7 fixed stuff
if (CRYPT_BLOWFISH == 1) {
$blowfish_salt = '$'. $method .'$07$'. substr($salt, 0, CRYPT_SALT_LENGTH) .'$';
return crypt($pass, $blowfish_salt);
}
return sha1($pass . $salt);
}
Making the salt unique per user adds a step, a db lookup for the supplied username's id ... I figure it's worth it. Am I wrong about that? Is there anything else I'm not considering here?
The whole point of salting is to produce different encrypted strings from the same password. If you use the same salt every time, this will not happen, so you may as well not use salts at all. You should be creating a random new salt for every password, and then storing it in the database alongside the encrypted-and-salted string.
I'm trying to transition to Blowfish for an authentication system. Bear with me, I'm not a cryptographer and my understanding of Blowfish is not quite there yet.
The current setup uses sha1 and salts. The salts are generated for each user and stored in the database. It boils down to this:
$salt = $this->getSalt($username);
$hash = sha1($password . $salt);
if ($hash == $hashInDB)
{
// user is authenticated, set session id etc ...
}
The getSalt() method gets the salt stored in the database for the specified user.
Now if I understand everything correctly, with crypt I should be doing:
$salt = '$2a$07$' . $this->getSalt($username) . '$';
$hash = crypt($password, $salt);
if ($hash == crypt($password, $saltInDB))
{
// The user is authenticated, set session id etc..
}
To clarify, for the second example the $saltInDB variable, is a value like `'$2a$07$arandomsaltcreatedatregistration$'.
Am I doing it right?
Your example is almost correct.
When you create a hash with the crypt() function, you will see that the used parameters (algorithm, cost and salt) are part of the generated hash (the begin of the hash):
$2a$07$LCzy1mE0b9lS8Uyx9HEeUgHm8zH1iDDZ5...
That means, you can replace $saltInDB with $hashInDB, the crypt() function will extract the needed parameters automatically from $hashInDB. This also answers your question about storing the salt, just store the hash value in the database, the salt is included there. And yes you should generate a new salt for each password.
The '$' after the salt is not needed.
More information about how to generate a bcrypt-hash you can find here, if you are looking for a well established library, i can recommend phpass.
I have read from this article http://codahale.com/how-to-safely-store-a-password/ and it says using a salt isn't even safe against GPU brute force attacks. I don't want to get hacked and have passwords decrypted in a few weeks... So I read some more and the solution was bcrypt however I don't want to implement the phpass class, I like SHA-512.
However if one can add rounds to sha-512 to slow down GPU attacks... how can that be done? Does rounds mean iterations?
How do you add rounds to slow down sha512?
One of the most secure ways for storing password that I found is following:
<?php
function createPasswordSalt($saltLength = 20) {
return substr(md5(uniqid(rand(), true)), 0, $saltLength);
}
function createPasswordHash($password, $salt = null, $staticKey = null) {
if ($staticKey === null) {
$staticKey = "Some passphrase that will be only in your php script";
}
if ($salt === null) {
$salt = self::createPasswordSalt();
}
return hash_hmac('sha512', $password . $salt, $staticKey);
}
And I store in database password and hash...
So here I have used multiple layers of security. And one can only hack your passwords if he get your database and php scripts together. In any case if the hacker has your scripts he can hack any password you have in your database as he knows the scheme that you use for hashing passwords.
Increasing the rounds for SHA512 does not mean iterating over an already hashed value with the same hash function. This can actually LESSEN the security given, as after the first hash, your new 'password' has a reduced character set. See this link on security.stackexchange which explains partially, why.
I suggest NOT 'rolling your own' password securing function. Instead use a much more well researched and vetted solution such as PHPass.
On their site is also a very well written and in depth article explaining the security implications of password hashing and creation.
I'm using the Auth Module in Kohana v 2.3.4.
In terms of authenticating users, there's a two step process. The entry point is the function login. It's first task is to retrieve the password stored in the database and retrieve the password and determine the salt value. The salt is supposedly determined by an array of values, each corresponding to a point in the $salt.$password hashed value to introduce yet another part of the salt. In my case, I'm using md5.
Problems:
I can't find a configuration for this SALT value. It seems to be relying on one already present within the password stored in the database. Is there one or do I need to configure AUTH to do so since this login needs to be portable and reproducible? If it can't detect the salt, in the hash_password routine, it defaults to using uniqid(), which I don't believe is portable at all.
In terms of adding users, does it make sense to modify the Auth library to add this feature? ie, introduce my own customized SALT that I can say, do an MD5 hash on that and then use that md5 generated by the salt to seed the password at given points in the md5sum?
I'm no security expert, but is this overkill? Granted, it prevents someone who were to get access to the md5 password list from using a md5 lookup of predetermined hashes.
If you have used the Kohana PHP framework, if you have any lessons learned or experiences after using it that might give insight as to the right approach for this problem, let me know. I'm reading numerous forums and wiki's about it, and there isn't a real concrete opinion yet that I've seen. I'm essentially trying to get a reproducible approach for authenticating someone in this site, both using PHP and eventually from a mobile device, like an iPhone. I'm also thinking of eventually adding support for google friend connect for openID support and integration.
Below are snippets from the Auth module in Kohana concerning the functions of interest. They have some debugging in them as I'm trying to better understand what's going on.
public function login($username, $password, $remember = FALSE)
{
if (empty($password))
return FALSE;
if (is_string($password))
{
// Get the salt from the stored password
$salt = $this->find_salt($this->driver->password($username));
Kohana::log('debug', "--- Auth_Core login salt = $salt ");
Kohana::log('debug', "--- Auth_Core login pass = $password ");
// Create a hashed password using the salt from the stored password
$password = $this->hash_password($password, $salt);
}
Kohana::log('debug', "--- Auth_Core login pass_hash = $password ");
return $this->driver->login($username, $password, $remember);
}
public function find_salt($password)
{
$salt = '';
foreach ($this->config['salt_pattern'] as $i => $offset)
{
// Find salt characters, take a good long look...
//$salt .= $password[$offset + $i];
$salt .= substr($password, $offset + $i, 0);
}
return $salt;
}
public function hash_password($password, $salt = FALSE)
{
Kohana::log('debug', "--- Auth_Core Original Pass = $password ");
if ($salt === FALSE)
{
// Create a salt seed, same length as the number of offsets in the pattern
$salt = substr($this->hash(uniqid(NULL, TRUE)), 0, count($this->config['salt_pattern']));
Kohana::log('debug', "--- Auth_Core salt created = $salt ");
}
// Password hash that the salt will be inserted into
$hash = $this->hash($salt.$password);
// Change salt to an array
$salt = str_split($salt, 1);
// Returned password
$password = '';
// Used to calculate the length of splits
$last_offset = 0;
foreach ($this->config['salt_pattern'] as $offset)
{
// Split a new part of the hash off
$part = substr($hash, 0, $offset - $last_offset);
// Cut the current part out of the hash
$hash = substr($hash, $offset - $last_offset);
// Add the part to the password, appending the salt character
$password .= $part.array_shift($salt);
// Set the last offset to the current offset
$last_offset = $offset;
}
Kohana::log('debug', "--- Auth_Core hashpw = $password + $hash ");
// Return the password, with the remaining hash appended
return $password.$hash;
}
Problem 1. The salt configuration is stored in config/auth.php. Find that file in modules/auth/config, then in your app/config folder (as you might have already known, Kohana uses cascading file system mechanism). The default file, which you are encouraged to customize into app/config/ folder, looks like below:
<?php defined('SYSPATH') OR die('No direct access allowed.');
return array
(
'driver' => 'ORM',
'hash_method' => 'sha1',
'salt_pattern' => '1, 3, 5, 9, 14, 15, 20, 21, 28, 30',
'lifetime' => 1209600,
'session_key' => 'auth_user',
'users' => array
(
// 'admin' => 'b3154acf3a344170077d11bdb5fff31532f679a1919e716a02',
),
);
Problem 2. In my opinion, the password hashing mechanism used by Auth, which is SHA1 with salt insertion, is quite secure provided you keep your salts, i.e. your auth.php file, secure.
Problem 3. Auth built-in hashing mechanism uses SHA1, which is relatively more crack-proof than MD5, so I would say don't do the MD5 way, no matter how complicated your scheme might look. A security expert Thomas Ptacek in his blog wrote:
No, really. Use someone else’s
password system. Don’t build your own.
Most of the industry’s worst security
problems (like the famously bad LANMAN
hash) happened because smart
developers approached security code
the same way they did the rest of
their code.
Problem 4. Yup I'm using Kohana to build my small company website and some of our clients' website and so far I don't find any problem with the Auth module, although I can't say much since I haven't really used it for real security-concerned website. But in general, I'd say Kohana is an excellent framework especially with the cascading filesystem mechanism.
Regarding point 1, the hash_password() function is used both to generate the password hash (against the salt and including the salt) that is stored in the database (e.g. at signup-time), as well as to recreate that hash when the password needs to be verified (e.g. at login-time). The hash_password() function will encode any salt that is given (or uniqid() if none is given) in the password-hash itself; that's a form of encryption where the salt_pattern is the key; if the salt_pattern can be kept secret, then that provides additional security since an adversary will not be able to do offline brute-forcing of the hash since the method of hashing is not reproducible (if the salt_pattern can be kept secret):
// Signup time; forget about uniqid(); you can use any salt that
// you please; once the password hash is stored in the database there
// is no need to know where your salt came from since it will be
// included in the password hash.
$password_hash = hash_password($password, FALSE);
// Login time; note that the salt is taken from the password hash itself.
$reproduced = hash_password($password, find_salt($password_hash));
$verifies = $password_hash == $reproduced;
The hash_password() function will first hash the password against the salt, and then insert each char of the salt into the password hash at the corresponding salt_pattern offset. find_salt() will extract these salt chars so that the hash can be reproduced. You can see it as hash_password() encrypting the salt and find_salt() decrypting it. Although you can also see it has hash_password() hiding the salt and find_salt() finding it, this method of encryption can't be called steganography, I think, because it is clear from the code that there is a salt stored with the password hash (the existence of the salt is not secret).
Regarding point 2, using your own salt is straightforward and fully compatible with the Auth module and an already existing database.
Regarding point 3, using a per user salt (uniqid() by default) is not overkill. Especially with MD5 which is broken for security purposes and where finding collisions is already practical with today's technology. Even better would be to use bcrypt() which uses a purposefully slower hashing algorithm to thwart brute-forcing attempts.
Regarding point 4, I haven't used the Kohana framework before, but reproducing or porting the Auth module is straightforward. Care must be taken that the salt_pattern is not forgotten or lost since it is an essential part of the hashing algorithm. The salt_pattern should also be kept secret since it is the only thing that keeps a determined adversary from brute-forcing the password hashes. uniqid() is just a reasonable default and can be replaced with whatever you want (as long as it is per-user and not a constant site-wide value.)
Also, there is a very good answer here on stackoverflow regarding portable bcrypt() and PHP. Naturally that will not be compatible with the Auth module, but I'd like to mention it anyway since it's just best practice to use a slow hash and not to rely on secrets that are difficult to keep, like the salt_patten.