Hashing (with salts) Username and Password in php
Salting protects against rainbow tables, so having 2 salts isn’t going to be any better than 1. The hacker needs to know the salt in order to crack your password with a rainbow table, the only way they can do that is if they have access to the database table. And if they have that they have both salts anyway.
The longer the password the harder it will be to do it with brute force, so a longer password is going to be better than extra salt.
Salting and hashing your username will add unwanted over-head every time you read the username from database. With the password you only need to salt and hash at log-on.
Ideally use something like BCrypt where the cryptographic hashing function can be adaptively slowed down over time as moore’s law continues. This will reduce the chance of a brute force attack.
I’d say that hashing the username is overkill, as is two salts for the password. One salt would be sufficient.
Be sure to use a secure hashing algorithm, such as SHA-512.
OK, so I think I’ve worked out that everyone says it’s overkill, but am I right in thinking it’s not wrong or less secure.
It is recommended to use a slow hash function like bcrypt, other hashes, even if they are technically safe, can be brute forced ways too fast.
Like others said, hashing username is overkill and one salt is enough. Use algorithm which is mathematically slow — it would be slow for the cracker too.
Salting your password once is enough. Having two salts is basically equivalent to generating a longer salt.
Hashing usernames will make it more difficult for you to manage your users than making the login more secure. Consider making a list of your current users, but all you have is the hashed versions? Remember that the point of hashing is to an irreversible ‘encryption’ of your data.
Consider using crypt() for hashing your password. Especially notice the Blowfish method as this is considered to be the safest hashing method currently.
I just answered another SO question going into great detail on how to handle logins and password security. It may be worth a read. (Some tidbits: Username has no need to be salted. Password definitely should be salted, but once is all you need. I use SHA-256.)
Your great lengthy post doesn’t mention Key Derivation Functions and their benefits over cryptographic hashes.
There really is no need to hash you username field, that should be something you are willing to display on the webpage while keeping your system secure. That being said, while it is unnecessary, it can’t hurt if your willing to put up with it.
Adding two salts is rather pointless if they both come from and are stored in the same place. Rather than doing this, I would use a permutation of the username as a salt, along with a long random string that you randomly generate and store in your database. If you are still paranoid, (which, I would guess you are by the whole «hash the usernames» thing) I would consider adding a third salt which you use throughout your application.
Make Sure You Use a Strong Hash Function
Make sure you use a secure hash function. whirlpool, sha256 and up, tiger, or whatever else you can use (check hash_algos()). Also, take a look at implementing bcrypt, which is very slow ( How do you use bcrypt for hashing passwords in PHP? ).
Correct way of creating salted hash password
sha512 cannot be undone. It is a one-way transformation @Vijayaragavendran the only way around it would be to generate a rainbow table for all strings starting with the $salt , which is why I prefer to suffix the $salt instead of prefixing it.
Also see Openwall’s PHP password hashing framework (PHPass). Its portable and hardened against a number of common attacks on user passwords. The guy who wrote the framework (SolarDesigner) is the same guy who wrote John The Ripper and sits as a judge in the Password Hashing Competition. So he knows a thing or two about attacks on passwords.
3 Answers 3
The SHA* algorithms are not appropriate to hash passwords, because they are ways too fast, and therefore can be brute-forced too fast. Instead one should use a slow algorithm like BCrypt or PBKDF2 with a cost factor, which controls the necessary time.
PHP supports the BCrypt algorithm with the new function password_hash(). There also exists 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);
It is recommended that you do not pass your own salt, instead let the function create a cryptographically safe salt from the random source of the operating system.
The salt will be included in the resulting hash-value, so you don’t have to store it separately. Just create a 60 character string field in your database and store the hash-value. The function password_verify() will extract the used salt from the stored hash-value. For more information you can have a look at my tutorial about storing passwords.
Хэширование паролей в PHP 5.5 с использованием нового API
Использование BCrypt является общепринятым и лучшим способом для хэширования паролей, но большое количество разработчиков по-прежнему используют старые и слабые алгоритмы, вроде MD5 и SHA1. Некоторые разработчики даже не используют соль для хэширования. Новый API хэширования в PHP 5.5 ставит своей целью привлечь внимание к BCrypt, упрощая работу с ним. В этой статье я расскажу об основах использования нового API для хеширования в PHP.
- password_hash() — используется для хэширования пароля.
- password_verify() — используется для проверки пароля на соответствие хэшу.
- password_needs_rehash() — используется для проверки необходимости создать новый хэш.
- password_get_info() — возвращает имя алгоритма хеширования и различные параметры, используемые при хэшировании.
password_hash()
Хотя функция crypt() довольно безопасна, она, по мнению многих, слишком сложная. Некоторые разработчики, чтобы не возиться с ней, используют слабую соль и слабый алгоритм для генерирования хэша, например:
Но функция password_hash() позволяет упростить нашу жизнь и обезопасить наш код. Когда вам нужно получить хэш пароля, просто скормите его в эту функцию, и она вернет хэш, который можно хранить в базе данных.
Вот и все! Первым параметром является строка пароля, который необходимо захэшировать, а второй параметр определяет алгоритм, который должен быть использован для генерирования хэша.
Алгоритм по умолчанию, в настоящее время, BCrypt, но более сильный алгоритм может быть установлен по умолчанию, когда-нибудь в будущем, и, возможно, он будет генерировать большие строки. Если вы используете PASSWORD_DEFAULT в ваших проектах, обязательно храните хэш в колонке, размером больше 60 символов. Установка размера колонки до 255 может быть хорошим выбором. Вы также можете использовать PASSWORD_BCRYPT в качестве второго параметра. В этом случае результат всегда будет 60 символов.
Главное здесь в том, что вам не нужно заботиться о значении соли и стоимости вычисления хэша. Новый API будет делать это за вас. И соль является частью хэша, так что вам не придется хранить его отдельно. Если вы хотите использовать вашу собственную соль (или стоимость вычисления), вы можете сделать это путем передачи третьего аргумента функции:
custom_function_for_salt(), //write your own code to generate a suitable salt 'cost' => 12 // the default cost is 10 ]; $hash = password_hash($password, PASSWORD_DEFAULT, $options);
Таким образом, Вы будете всегда идти в ногу с актуальными мерами безопасности. Если PHP позже примет решение о применении более мощного алгоритма хеширования, ваш код может воспользоваться им без изменений.
password_verify()
Теперь, когда вы видели, как генерировать хэши с новым API, давайте посмотрим, как проверить пароль. Мы просто берем хэш из базы, и пароль, введенный пользователем и передаем их в эту функцию. password_verify() возвращает true, если хэш соответствует указанному паролю.
Соль является частью хэша и именно поэтому нам не придется возиться с ней отдельно.
password_needs_rehash()
Что делать, если вам нужно изменить соль или стоимость вычисления для сохраненных паролей? Например, вы решили усилить безопасность и увеличить стоимость вычисления или изменить соль. Или PHP изменил алгоритм хэширования, используемый по умолчанию. В этих случаях вы хотели бы изменить существующие хэши паролей. Функция password_needs_rehash() проверяет, использует ли хэш пароля конкретный алгоритм, соль и стоимость вычисления.
12])) < // the password needs to be rehashed as it was not generated with // the current default algorithm or not created with the cost // parameter 12 $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' =>12]); // don't forget to store the new hash! >
Имейте в виду, что вам нужно сделать это, когда пользователь авторизуется на сайте, так как это единственный раз, когда у вас есть доступ к его незашифрованному паролю.
password_get_info()
- algo — константа, которая идентифицирует конкретный алгоритм
- algoName — название используемого алгоритма
- options — различные опции, используемые при генерации хэша
Заключение
Новый API хэширования паролей, безусловно, удобнее, чем возня с crypt(). Если ваш сайт в настоящее время работает на PHP 5.5, то я настоятельно рекомендуется использовать новое API хэширования. Те, кто используют PHP 5.3.7 (или более новой версии), могут использовать библиотеку под названием password_compat которая эмулирует это API и автоматически отключает себя при использовании PHP версии 5.5+.