I have a super old version of php (please don't tell me to upgrade for it will never be an option in our case) and i need to store passwords. I had seen posts like this and many more that says, use crypt() of php. I am just confuse with one thing:
My question is which is proper way of storing password; Use ONE SAME SALT for all passwords of different users or DIFFERENT RANDOMLY GENERATED SALT for each password of users?
My question arise because in my experience, i haven't seen a database/table with salt in each row, some have a one salt in a config file and it is being used for salting all of the passwords. Also, i think storing different salt in each user simply means more bytes to store.
Thanks guys ♥
You want to use a different salt. The idea being is that a salt will impact the resulting hash.
When "hacking" passwords that have been exposed, malicious people will use "rainbow tables". These are essentially a reverse look up that finds strings that hash to the given value. Rainbow tables can also be generated for common passwords.
If you use one salt, a hacker will only have to generate one rainbow table. If you use a new salt for each password, the hacker has to generate rainbow tables for each password they wish to compromise.
It is relevant to upgrade your PHP for modern hashing librarys (like bcrypt). However, there are back-ports for older versions of PHP which I seriously recommend. Hashing functions for passwords are designed to be computationally expensive so that a password takes time to verify. The idea being that you cannot verify 1000 different password possibilities in any reasonably short amount of time.
Create a unique salt for each password, this is the only safe method. How you can calculate the hash, depends on how old your PHP version actually is:
Version 5.5 of PHP will have built-in support for BCrypt, the functions password_hash() and password_verify(). This function will generate a safe salt on its own and includes it in the resulting hash-value.
For PHP version 5.3.7 and later, there exists a compatibility pack, from the same author that made the password_hash() function. You can then already use the password_hash() function, and should you switch to a newer PHP version you do not have to change your code.
For PHP versions before 5.3.7 there is no support for crypt() with 2y, the unicode safe BCrypt algorithm. One could use the compatibility pack and replace it instead with 2a, which is the best alternative for earlier PHP versions.
For PHP versions before 5.3, there is no support for BCrypt at all. Your best bet will probably be the phpass framework then.
Note that the crypt() function will not create a safe salt on its own, though it will include it in the resulting hash-value. For verification it will extract it from there.
Using a single salt for every hash will always prevent a rainbow table attack unless a specially generated rainbow table is generated using the salt you were using, which is astronomically impossible unless your salt is a single character or was known beforehand.
Using the same salt for every hash is also great against hackers that have access to your SQL database but not your back-end code.
However if a hacker has access to your static salt it makes having it almost useless against the speed of a brute-force attack, which having a salt for every user would mitigate.
You should use both a hard-coded static salt and a dynamic salt to both prevent a rainbow table attack and mitigate a brute-force attack.
Related
Use SHA512 as encryption in Multicraft panel (which you can change the settings for MD5), but I need to use an older version of the same database. This old version did not have the option to encrypt with SHA512, but only with MD5. Thus, all passwords are invalid with MD5.
It's possible convert all SHA512 passwords in MySQL database to MD5?
SHA512 and MD5 are hashes, not encryption algorithms. By design, they are not reversible.
The only way to convert these values is to wait for each user to log in, validate their password against the existing SHA512 hash, and rehash¹ their input with MD5. This is the reverse of how password hashes are updated to more secure standards.
But please, please, don't do this. MD5 is hopelessly broken. You would be doing your users a huge disservice to revert from SHA512 to MD5. Find a way to use the newer version of your software.
¹As noted by zaph in a comment, "rehashing" is an oversimplification, and depending on how your panel is actually implemented it might be using insecure password storage today.
To provide reasonable security each password must also have a unique random salt (which protects against things like rainbow tables) and each hash must be iterated enough times to make brute forcing impractical. As computers get more powerful the number of iterations must be increased. Today it is common to iterate tens or hundreds of thousands of times.
Cryptography is shockingly difficult to get right. Instead of trying to follow all the best practices manually, use libraries and functions that operate at the right level of abstraction and have been audited for security. An algorithm like bcrypt (via PHP's built-in password_hash function, where it is currently the default algorithm) would be a good choice.
Short answer: No.
Long answer:
By design, both MD5 and SHA512 are one-way hashes. In order to convert SHA512 to MD5, you would need to know both the original password for every password your are trying to convert, and also the salt that was used to encrypt them. You almost certainly wouldn't know every password for every one of your users.
One-way hashes work by actually casting the same algorithm every time a user logs in. The user types in their password, the algorithm is applied to it, and if it perfectly matches the copy in the database that has already been hashed, then the user is logged in. You can't use any sort of algorithm to work out what the original password was, only to compare if the output of applying a specific password would be to a password that is already encrypted.
MD5 is also a far weaker hashing algorithm than SHA512. Converting to MD5 would make your password far less secure, and this would be something that you probably wouldn't want to do. Instead, you should be looking at a way to incorporate the new database system.
basically,
$stored_hash = strrev(md5($plain_text));
Because, now rainbow tables and pre-computed attacks might get a hit on the hash, but when the attacker types in the calculated plain text, it will not authorize because the orginal hash is computed differently.
can i implement this on my app?
You should not use MD5 for hashing passwords; even though certain "tricks" may make it harder to reverse engineer passwords, rainbow tables for reversed passwords may already exist, and if they don't they can be generated.
See this article from PHP on the issue. Essentially it boils down to that you should use password hashing functions that are provided by PHP. Using these has the additional advantage that, when you run your application on a future version of PHP, it may use a more secure hashing algorithm than it does now.
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.
I'm the developer of a new website built in PHP and I'm wondering what exactly is the best
thing to use for hashing. I've looked at md5 and sha1 but is there anything more secure.
I'm sorry if this is a nooby question but I'm new to PHP Security and I'm trying to make my
site as secure as possible. Also what is a salt?
Thanks,
Waseem
First off md5 and sha1 have been proven to be vunrable to collision attacks and can be rainbow
tabled easily (When they see if you hash is the same in their database of common passwords).
There are currently two things that are secure enough for passwords, that you can use.
The first being sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be
vunrable to collision attacks and sha512 will generate a 512 bit hash. Here is an example of
how to use sha512:
<?php
hash('sha512',$password);
The other option is called bcrypt. bcrypt is famous for its secure hashes. Its
probably the most secure one out there and most customizable one too.
Before you want to start using bcrypt you need to check if your sever has it enabled, Enter
this code:
<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
echo "CRYPT_BLOWFISH is enabled!";
}else {
echo "CRYPT_BLOWFISH is not available";
}
If it returns that it is enabled then the next step is easy, All you need to do to bcrypt a
password is (Note for more customizability you need to see this How do you use bcrypt for hashing passwords in PHP?):
crypt($password, $salt);
Now to answer your second question. A salt is usally a random string that you add at the end of
all you passwords when you hash them. Using a salt means if some one gets your database
they can not check the hashes for common passwords. Checking the database is called using a rainbow table. You should always use a salt when hashing!!
Here are my proofs for the SHA1 and MD5 collision attack vulnerabilities:
http://www.schneier.com/blog/archives/2012/10/when_will_we_se.html, http://eprint.iacr.org/2010/413.pdf, http://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf, http://conf.isi.qut.edu.au/auscert/proceedings/2006/gauravaram06collision.pdf and Understanding sha-1 collision weakness
The whole purpose of the salt is to slow down an attacker from comparing a list of pre-generated hashes against the target hash.
Instead of needing to pre-compute one "hashed" value for each plaintext password, an attacker needs to precompute 16384 "hashed" values for each plaintext password (2^7 * 2^7).
That kinda pales today but was pretty big when the crypt function was first developed - the computational power to pre-compute that many passwords times the number of plaintext password you suspect (dictionary) was pretty high.
Not so much today which is why we have things like shadow passwords, other core password functions besides crypt and every sysad wanting you to pick a password that would not show up in a dictionary.
If the hashes you want to generate are for passwords this is a well accepted method of implementing it.
http://www.openwall.com/phpass/
If you're planning to do this for passwords, then do not use MD5 or SHA1. They are known to be weak and insecure, even with salt.
If you're using them for other purposes (eg providing a hash of a file to confirm its authenticity, or a random hash database column to provide a pseudo-random sort order) then they are fine (up to a point), but not for passwords or anything else that you would consider needing to be kept secure.
The current best-practice algorithm for password hasing is BCrypt, with suitable salting.
And the best way to implement BCrypt password hashing in PHP is to use PHP's new password API. This API will be featured as a set of built-in functions in the next version of PHP, v5.5, due for release in the next few months. The good news is that they have also released a backward-compatibility version for users of current versions of PHP (5.3 and 5.4), so even though PHP 5.5 isn't released yet, you can start using the new API immediately.
You can download the compatibility library from here: https://github.com/ircmaxell/password_compat
Also: You asked what "salt" is. Since I've mentioned it a couple of times in this answer, I should address that part of the question too.
Salt is basically an additional string added to the password when hashing it, in order to make it harder to crack.
For example, an attacker may know in advance what the hashed value is for a given password string, or even a whole lot of given password strings. If he can get hold of your hashed data and you haven't used a salt, then he can just compare your hashes against his list of known passwords, and if any of your users are using an easy to guess password, they'll be cracked in seconds, regardless of what hashing method was used.
However, if you've added a secret extra string to the password when you hash it, then the hashed value won't match the standard hash for the original password, thus making it harder for the attacker to find the value.
The good news is that if you're using the API I mentioned above, then you don't need to worry too much about the details of this, as the API handles the salting for you.
Hope that helps.
I have a user table in my mysql database that has a password column. Currently, I use the MD5 algorithm to hash the users' password for storage in the database. Now I like to think that I am a security conscience person. I noticed while reading the MySQL docs that they don't recommend MD5 or the SHA/SHA1 hashing methods, but don't offer an alternative.
What would be the best way to hash my passwords in MySQL? A function that is natively supported in both PHP and MySQL would be ideal and necessary with my current implementation.
Thanks!
It's not necessarily that you shouldn't use MD5, as much it's that you shouldn't use just MD5, as this leaves you vulnerable to rainbow-table attacks (a rainbow table is a table of precomputed hash values - if your password is even remotely common or simple, the attacker needs merely to look up the hash and he knows your plaintext password.)
At the very least you should add a salt to every password so that any existing rainbow table is useless, forcing the attacker to generate an entire new rainbow table just for your database of passwords.
Better still is to use a different salt for every password in your database, say the username it's associated with, so that an attacker can't even generate a rainbow table for your whole database and has to crack each entry separately.
MD5 is also a very fast algorithm. Speed is the enemy when it comes to cracking - the longer it takes to generate a hash, the longer it takes for each attempt a hacker makes. Something simple like hashing the plaintext 100 times with a new additional salt each time would be barely perceptible (if at all) to a user logging in to your site, but it would increase the time it takes to brute-force a password by the same 100 times.
Far, far more detail here: http://www.codinghorror.com/blog/archives/000953.html
MD5 is considered to be weak by today's standards. It would still take some work to crack a hash made with MD5, but it's several times easier than guessing the password by brute-force. Ideally, cracking a hash should not be easier than brute-force.
SHA1 is also considered easier to crack than guessing the password by brute-force.
I actually contributed a patch to MySQL to surface the SHA224, SHA256, SHA384, and SHA512 functions from OpenSSL. These are recommended by NIST for password hashing (actually SHA256 and higher).
My patch was finished by MySQL engineers, and is included in MySQL 6.0.5 and later, if I recall.
If you use an earlier version of MySQL (and who doesn't), then you can probably use an implementation of strong hashing functions in your host language. PHP has the hash() function for example. You can do the hashing in your application and save the resulting message string to the database.
Don't forget to do salting, too!
This question is 7 years old. In that time we have progressed in computing to where MD5 and SHA1 are now easily broken by modern computers. These should be avoided now.
With PHP 5.5 came the introduction of password_hash, which uses the far more secure bcrypt algorithm. While MySQL can encrypt/decrypt bcrypt, it's a terrible solution because you're not only adding a potentially large computation load to your database layer, but the unhashed password could be stored in your logs
Under no circumstances should a plain text password hit MySQL, even if at the query level. Otherwise you risk writing the passwords to log (query log, general log, slow query log, etc). Which is horrific. So no, don't even bother...
MD5 and SHA-1 probably aren't recommended anymore due to know attacks. But, they're still generally sufficient for most use cases.
If you're looking for more options, just use PHP's hash functions -- you've got plenty of options there.
I am using a combination. For example SHA1(MD5()) is working fine.