Opinions on Dual-Salt authentication for low sensitivity user accounts? - php

I am currently working on a web project requiring user accounts. The application is CodeIgniter on the server side, so I am using Ion Auth as the authentication library.
I have written an authentication system before, where I used 2 salts to secure the passwords. One was a server-wide salt which sat as an environment variable in the .htaccess file, and the other was a randomly generated salt which was created at user signup.
This was the method I used in that authentication system for hashing the password:
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//create a random string to be used as the random salt for the password hash
$size = strlen($chars);
for($i = 0; $i < 22; $i++) {
$str .= $chars[rand(0, $size - 1)];
}
//create the random salt to be used for the crypt
$r_blowfish_salt = "$2a$12$" . $str . "$";
//grab the website salt
$salt = getenv('WEBSITE_SALT');
//combine the website salt, and the password
$password_to_hash = $pwd . $salt;
//crypt the password string using blowfish
$password = crypt($password_to_hash, $r_blowfish_salt);
I have no idea whether this has holes in it or not, but regardless, I moved over to Ion Auth for a more complete set of functions to use with CI.
I noticed that Ion only uses a single salt as part of its hashing mechanism (although does recommend that encryption_key is set in order to secure the database session.)
The information that will be stored in my database is things like name, email address, location by country, some notes (which will be recommended that they do not contain sensitive information), and a link to a Facebook, Twitter or Flickr account. Based on this, i'm not convinced it's necessary for me to have an SSL connection on the secure pages of my site.
My question is, is there a particular reason why only 1 salt is being used as part as the Ion Auth library? Is it implied that I write my own additional salting in front of the functionality it provides, or am I missing something?
Furthermore, is it even worth using 2 salts, or once an attacker has the random salt and the hashed password, are all bets off anyway? (I assume not, but worth checking if i'm worrying about nothing...)

It is because Ion_Auth uses bcrypt - so you generally dont need to do much more.
Furthermore - you can configure "random_rounds", which is kind of like a random salting (to a degree) in the config.
edit: you can view this SO thread for more details on bcrypt and other types of encryption

The argument that someone may somehow find a way to inject code, or you mistakenly leave a directory open to view, or someone finds an injection hack and can see the system salt file or the user data isn't that compelling of a reason to use dual salts. If any of this, indeed you'd have more to worry than a list of the user salted and encrypted passwords!
All this being said, the dual salt solution is indeed much more secure, especially if there's a chance someone else other than you will see the system salt in your code. Think of a situation where maybe a contractor or a co-worker leaves. If they know the salt and the salting patter/algorithm used they can create rainbow tables and use that against your site. Adding the second random salt to the user record, protects against this.
It's all about weighing the value of what your securing vs. the amount of reasonable effort someone would need to go through to get at what your securing. Also, simply not being completely negligent by not using salts at all or not encrypting at all is sadly better than many other less secure places our basic data is stored. If it's no credit info, medical records, social sec. numbers, and just vanilla user info (email, address, etc...) and you have no plans to ever bring in this data, single salt is probably sufficient. If you can't make this judgment call with 100% certainty now, error on the side of the more secure option.

Related

PHP CRUD application, password hasing

I know this is a topic talked about a bit, but I want to ask specifically about my application. It's also worth mentioning that I'm fairly new to PHP, and have been learning as I go.
So I wrote a seemingly basic CRUD application, using PHP and MySQL. All of my code is using mysqli_*, and I've tried to use best practices where I could. One thing I have done that most people frown upon is using MD5 to hash my passwords. I think I understand the purpose of using SHA1, as it's supposed to require more cycles than MD5 to hash/unhash, and the salt is supposed to prevent the use of rainbow tables. bcrypt is a newer hashing algorithm, requiring even more cpu cycles than SHA1. At least I think this is how everything is.
It's my understanding that you hash/salt passwords, so if someone gains access to your users table in your database, they don't see your users passwords in plain text. Right?
With my application being a somewhat basic CRUD system (inventory tracking for a small business, with multiple users and definable locations), if someone was to gain access to my users table and see these MD5 hashes, they could easily reverse that into readable passwords and log into my system. However, if they gain access to my database and see my users table, then they could easily see my inventory table, and products table, and all the other tables in the database, getting the data without needing to log into the application. Currently, my web server has PHPMyAdmin and Webmin (with the MySQL module) so if they gain access to either of those, they can see the data in the database and not be concerned with logging into the system itself.
With this in mind, what would be the best practice in this case? I have typical security on my web sever already, such as preventing root SSH access, iptables, etc., but as far as password hashing, should I bother upgrading my code to use bcrypt instead of MD5? Is upgrading to use bcyrpt from MD5 an easy process to do, or would I have to re-engineer how my login system works?
Thanks!
From PHP.net
$hashed_password = crypt('mypassword'); // let the salt be automatically generated
/* You should pass the entire results of crypt() as the salt for comparing a
password, to avoid problems when different hashing algorithms are used. (As
it says above, standard DES-based password hashing uses a 2-character salt,
but MD5-based hashing uses 12.) */
if (crypt($user_input, $hashed_password) == $hashed_password) {
echo "Password verified!";
}
Doesn't look that hard, right? That in mind, passwords aren't the biggest vulnerabilities out there, it takes significantly more time to protect a site from all those XSS, CSRF and other neat stuff like that.
In other words, it isn't all that huge vulnerability, but if security is your first and foremost concern, go for it.
You should definitely switch to BCrypt, since MD5 is ways too fast and therefore can be brute-forced easily. You can calculate about 8 Giga MD5 hashes per second, that means you need only a fraction of a milisecond to try a whole english dictionary.
The best you can do is to use the new PHP function password_hash() to create a BCrypt hash.
// 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 exists also a compatibility pack for earlier PHP versions.
Having read access to the database (SQL-injection), does not mean that an attacker has full control of the server and can manipulate things.

PHP SECURITY dynamic generated user hash password on every login or hash system changes

I'm knowing this site http://www.openwall.com/phpass/, but idea is on salt on mainly system.
Example, ZEND use system('uname -a') and it's hashed to md5() for using ROW LEVEL user SALT encryption. This is combination of user password, user login name/email address and server name as sha1/md5/...
But, my idea is generate DYNAMIC SALT instead STATIC SALT such as system('uname -a'). Example, every time when user is logged in, SALT has been changed but not user password.
For more security reasons, i'm needing dynamicaly changes salt on database or external file on daily basis or using third-party such as checking data from another server for salting?
What are best method for securing user sensible data on users database table and currents login. Cookie also is very bad secure options for me. It's must works such as PayPal API Tokenize and user id...
I'm using current:
salt from every user
salt from system hashed
hashed combination of user password, user salt and system salt
SHA-512 crypt() or bcrpyt() class
dynamically salt ? idea?
You are doing it wrong.
I think you are missing a key fact about re-hashing the password. To do it, you would have to store it in a recoverable form. Thus, creating even greater security risk, if system is compromised.
Here is what i would do:
make passwords expire in 60 days (or, you can choose some other number, just not too often).
each time user sets new password, you generate a random salt
build hash with crypt(), using CRYPT_SHA512 or CRYPT_BLOWFISH hashing algorithms
set a bit higher amount of rounds .. 20'000 should be enough
store the whole result that crypt() returns in the hash field in db.
Also you might benefit for reading: Properly Salting Passwords, The Case Against Pepper.
Changing the salt doesn't improve anything.
The point is: you always need to store salt and hash together somewhere because when you compare the password input with the hash you need to hash the input - obvious, right?
So this is the point: even if you change the salt after every login and do some weird re-hashing of the password it changes nothing because as soon as an attacker gets the database he has both hash and salt (if it's stored there together, which is necessary if you always use a different salt for each user which is something you should do).
A far more better way is extending the hashing by using 1000-10000 rounds of hashing as well as a long salt (you can easy use 512 bytes for the salt). These are better tip's than doing some re-hashing.
But anyway: if you really want to improve your PHP application you should focus on avoiding security issues like SQL injection, XSS, CSRF, RFI, LFI, file disclosure, RCE, etc - if an attacker gets access to the server he can simply backdoor the login script to send him an e-mail containing the plaintext credentials every time someone tries to login. (Well, you can also avoid this if you use a challenge-response authentication implemented in javascript like CRAM-MD5 http://en.wikipedia.org/wiki/Challenge-response_authentication or using RSA (also implemented in JS) to securely send login data).
Salt is only used to prevent against precomputation attacks, such as Rainbow Tables. Thus if someone wants to bruteforce the hashes, they actually have to compute them one at a time at runtime. (and not merely do a lookup in a database of pre-computed hashed values)
It's not really clear what the problem is that you're trying to solve. You just say:
"For more security reasons, i'm needing dynamicaly changes salt"
If that problem is precomputation attacks, then just have a normal salt. If it is not a precomputation attack, then salt is almost surely the wrong solution.

Can this password be made more secure?

How do I make passwords more secure, my current code is:
<?php
if(!empty($_POST['userPass']))
#secure pass
$newRequesterPass = mysql_real_escape_string($_POST['userPass']);
$static_salt = 'M0AaE|}{<}|{&*#^AhEQ';
$dynamic_salt = mt_rand();
$newRequesterPass = sha1($dynamic_salt . $newRequesterPass . $static_salt);
?>
Is there a way to make this more secure, without sacrificing a ton of resources?
Like through SHA512, or another method?
You can change the algorithm to use SHA512 or Blowfish.
See http://php.net/manual/en/function.crypt.php
You could also look at generating a unique salt per user when they create their account (or update their password), which would limit the risk to a single account if the salt is discovered.
Using hash_hmac is better than plain hashing (md5/sha etc).
http://php.net/manual/en/function.hash-hmac.php
Although I dont understand your use of $dynamic_salt. If you generate a new salt each time, how is it going to match up with the password in the database.
..
Ok, so if the dynamic salt is stored per user....
$newRequesterPass = hash_hmac('sha256', $newRequesterPass, $dynamic_salt.$static_salt);
In addition to the excellent suggestion to use a stronger hash, secure password management involves management code that does more than store the password in salted+hashed form. How much of this you do depends on the business needs of your application, but consider the following:
Password validation -- you may want to enforce certain characters (e.g. letter + number, upper + lower case, etc.
Multiple hashes -- e.g. hash the password 1000 times -- OK this may violate your "not a lot of resources" condition :)
Expiration -- Passwords should be set to expire at some time (e.g. 1 year), so that you want to warn your users to change their password before then (e.g. 10 months) right after they successfully login.
Channel handling -- obviously the password should be sent via an SSL channel and not in the clear. Do not rely on client javascript to secure the password. But you should do more than just POST the password via https, the entire login sequence needs to be conducted in https.
Forgot password policy. Do not send them the password in the clear via email. Send them a link to reset their password and use an offline confirmation channel (e.g. send a follow up email notifying them that their password has been changed).
Take a look here https://www.owasp.org/index.php/Forgot_Password_Cheat_Sheet
UPDATE: Just to be clear, don't try to roll your own tools for session management or password hashing. Use the standard tools unless you are a real expert.
What you've goth there, is just "security by obscurity" - a very complicated way of creating a password hash.
If you are at all bothered about people compromising your database and cracking the hashes, you should use bcrypt.
If you're not, then use something standard (md5 is popular) - this provides only superficial protection against cracking.
Note that someone would need to compromise your database to be able to do dictionary or brute-force attacks in this way.
I strongly recommend that you don't "invent" cryptographic algorithms yourself, it is very difficult to get them right (or at least, make them secure).
md5() - Calculate the md5 hash of a string
hash() - Generate a hash value (message digest)
uniqid() - Generate a unique ID
Added :
sha1() — Calculate the sha1 hash of a string
Just see http://php.net/manual/en/function.crypt.php

Is this a safe way to store my passwords?

I've been reading around a few different guides/tutorials on this topic and found the following:
Storing Passwords Securely using Salt in PHP
Secure Hash and Salt for PHP Passwords (Top Answer)
I know that what I've read there is a very secure way to store a users password. I've made an attempt to combined the 2 slightly while instead of using mt_rand like in the first example, I've generated my own dynamic salt.
Here is my code:
<?php
$static_salt = ""; // Removed value for obvious reasons
$dynamic_salt_choice = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$dynamic_salt_length = 40;
$dynamic_salt = "";
$dynamic_salt_max = strlen($dynamic_salt_choice)-1;
for ($i = 0; $i < $dynamic_salt_length; $i++) {
$dynamic_salt .= substr($dynamic_salt_choice, rand(0, $dynamic_salt_max), 1);
}
$password_length = length($password);
$split_at = $password_length / 2;
$password_array = str_split($password, $split_at);
$password = $password_array[0] . $static_salt . $password_array[1];
$password_hash = hash_hmac('sha512', $password, $dynamic_salt);
?>
According to me this is fetching a static salt, generating a dynamic salt, we're then splitting the given password in 2 parts in an array and adding the static salt in between the two password sections.
We are then hashing the password with sha12 along with the dynamic salt.
My question to you is, is this more secure or just as secure as the 2 methods I've linked to? Or am I making it more vulnerable by mixing things up this way?
I also take it storing $password_hash in a cookie along side a username cookie for automatic login is a big no-no? If so, how do websites remember you through cookies in a secure manner?
I'm trying to increase the level of security with my sites
well, to let you know, no password hashing ussue can increase your site security even a bit.
You have to focus on the other, much more important things such as SQL and file injections, XSS and CSRF vulnerabilities. If you keep your site secure, it will keep your passwords as well safe just as a side effect.
Next thing you have to focus on, is password strength. No hash can secure a a silly password like joe or 123.
As for the hashing itself - you can use whatever you wish, some basic things like using some sane salt like registration time or email and some number of iterations of whatever hashing function is enough. Don't put too much meaning in hashing. it is not the thing that requires SO much attention as inventing some extra-secure original algorithm.
My question to you is, is this more secure or just as secure as the 2 methods I've linked to? Or am I making it more vulnerable by mixing things up this way?
Dunno if you trust me (I bet you won't) but ALL these methods are secure enough and require no impreovement. And affect no security of the site but only passwords themselves in case they are stolen using another vulnerability in your site.
I also take it storing $password_hash in a cookie along side a username cookie for automatic login is a big no-no?
I don't think it's wise thing to reveal a hash itself. But again, it affects no site security but passwords potential vulnerability only. If your hash and password are strong enough, a logic is making me to say that it is safe enough.
Assuming that the $dynamic_salt is stored alongside the final $password_hash -- since the hash wouldn't be testable without it -- this scheme is quite weak. Using a salt does protect against rainbow tables, but a non-iterated HMAC leaves this scheme weak to brute-force attacks. (The length of the salt does you no good, as it's a known constant in the hash input. Putting it in the middle of the original password doesn't really help either.)
Overall, this scheme is far weaker than bcrypt(), as it only (effectively) iterates the hash twice. You're really no better off than if you simply were storing the password using a simpler scheme such as:
$salt = uniqid();
$password_hash = hash_hmac('sha512', $password, $salt);
But you're still better off using someone else's (tried and tested) password encryption routine, rather than cooking your own.
With regard to using the password hash in a cookie -- this is to be avoided, as it allows an attacker with read-only access to the database (e.g, via a SQL injection attack or a stolen backup) to impersonate any user in your application without knowing or changing their password. It also means that, if a user's computer has been set to automatically log in, the password hash is stored on it. I'd avoid this.
A better scheme might be to set a randomly generated nonce in a cookie when a user chooses to log in automatically, then store a hash of that nonce in the database. This way, the server can check the correctness of a login key without ever having to "remember" it.
This seems like a reasonable salting scheme, although possibly overkill. It probably doesn't need to be 40 characters long - you're just trying to blow up the size of a rainbow table, not make an unguessable nonce - but making it long won't hurt.
As for autologin, you should store (in a cookie) a random token that corresponds to a database entry pointing to the user's account. When the user changes their password, erase all these entries for that user. When generating this token, rand() isn't good enough - you need a secure, unguessable random number. Unfortunately, PHP doesn't really have a built-in facility for secure random numbers - mt_rand() is about as close as it gets, but I personally would directly read random bytes from /dev/urandom on a Linux system and use that to generate my nonce.
Salts can be used,but it has got its own limitations. Another way is using bcrypt.More information can be found at http://www.openwall.com/phpass/
And i think This SO article is more than enough Secure hash and salt for PHP passwords

password/login system in php

For a login system in php would this be a suitable outline of how it would work:
users types in username and password, clicks login button.
Checks if user exists in database,
if it does, then retrieve the salt
for that user
hash the password and
salt (would this be done on the
client or server side? I think
client side would be better, but php
is server side so how would you do
this?)
check value against value in
database,
if the values match then
user has typed in correct password
and they are logged in.
Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt
No. This means you are hitting your database twice.
hash the password and salt (would this be done on the client or server side? I think client side would be better
No. The point of hashing the password is so that if someone compromises your database, they can't (easily) find out what they need to send to your system (or other systems) to log in as that user.
If you hash the password before sending it to the server, then the attacker can bypass the JS and send the prehashed password read from the database to your system.
User submits username and password
Password is hashed with the standard salt for the system
SELECT some,cols FROM your_users WHERE username=? and password=?
Count the number of rows returned from the database.
Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt (would this be done on the client or server side? I think client side would be better, but php is server side so how would you do this?)
The important thing to remember is that you never ever trust the user which means where authentication is concerned you should do as much as possible on the server side. Give the user as little information as possible and don't trust them with anything.
In regards to your question, the obvious point is that there is far more data transfer involved if you let the user precompute the hash. Rather than the single request and response there are 3 requests and responses required. It also increases the requirements from a browser to a browser with JavaScript enabled. Depending on your audience a lot of users can have JavaScript disabled (usually via the NoScript plugin).
Regarding security, while allowing the the user to see the salt wouldn't effect the defense against rainbow tables, showing them how you combine the salt and the password does.
Brute force attempts through the web interface are not that much of an issue anyway as hopefully you would only allow 5 (or so) login attempts per username per hour. Knowing the salt and hashing algorithm doesn't help at all (It just reduces your sever load ;) ). However if they have the database and know how to combine the salt and the hash it becomes that much easier to do a brute force attack.
While security through obscurity is no real defence, it does make your system that much harder to break, so I would reccomend that you don't attempt to do hashing on the client side.
It has to be Server Side
You are on the right track, but let me help you improve your system.
Generate a strong random key and store it in a file above your document root:
/home/username/key
/home/username/public_html/login.php
The file should contain (pseudo) random binary data with as much strength as possible. 512-bits of random data should be quite okay.
Then generate a unique salt for each user in your system. This salt does not have to be stronger than 16-bits of random binary data.
Finally, the password hashes should be something like:
hash('sha256', $password . $salt . $key);
where the hash algorithm matters a lot. Do not use MD5 or SHA-1. Use the SHA-2 family, typically SHA-256 or SHA-512. Also, Whirlpool is a good choice.
If you want to improve your system even more, you could iteratively hash again and again like:
public static function hash($algorithm, $data, $iterations = 1, $rawOutput = false)
{
if ($iterations < 1)
throw new Exception('There must be at least one iteration.');
while ($iterations--)
{
$data = hash($algorithm, $data, true);
}
return ($rawOutput ? (binary) $data : bin2hex($data));
}
Why such many moves?
Check if user exists in database, with given salted hashed password
if it does, then retrieve the user information
that's all
If you're talking of secure password transfer from client to the server - that's another story, you can refer to the HTTP digest authorization description for the schema. In short, it's client-side password hashing using random one-time token stored on the server side. OR SSL, of course
Most, if not all the form validation should be done on the server side. The users will be able to look at all client-side code and having any verification across a database done on the client-side will have massive security issues.
There might be different ways of approaching what you are trying to do. Here is what I would do:
Start a session if you want the user to be redirected somewhere and you need the username for that page
The general syntax for hashing in PHP is hash('nameOfHashFunction', $pswrd . $salt); you can cross verify this with the hash you have stored for the particular user.
The latest member of the SHA family is SHA-3, it was released in 2015. You can read more about it on its Wikipedia page. If there is a new member to the SHA family when you are reading this, I'd highly recommend you give it a light read and use that instead.
https://en.wikipedia.org/wiki/SHA-2
https://en.wikipedia.org/wiki/SHA-3

Categories