At the moment, my system is using a custom generate salt when the user registers which is then stored in the database along with their hashed password.
Now, I was thinking about having an option for users to define their own salt on registration. For an example, if they visit register2, they see 3 inputs:
Registerpage:
Email
Password
Custom Salt
So they fill out their email, password and set a custom salt-- whatever they want to be, in the limits of the hash function
$loginhash = hash_hmac('sha256',$password,$userdefinedsalt); //just for the post don't use
now, because they user has generated their own salt, that salt doesn't actually store in the database, only the hashed password.
Now the user has registered, every time they want to login, they must specify that custom salt they have created that hash with, use a POST get the inputs, hash them together and compare the passwords.
So if a malicious hacker somehow finds a way in to the database, they will have a useless hashed password, and no salt, therefore rendering that password useless? Yes or no?
Now, if another user doesn't feel like doing this, they can go the route of the system generated salt, that stores in the database etc.
Does this seem fesable for protecting users passwords?
What if a user forgets their salt?
They can go to the password reset, which will generate a custom hashed password with a salt, they can then login, and again perform the actions of creating another password with their salt, when doing so, it deletes the computer generated salt from the database to leave that blank.
Is this just asking for a world of hurt, is this a bad way?
It's the purpose of the salt, to prevent an attacker from getting all passwords with one single rainbow-table, nothing more nothing less. So better let the salt do its work and do not mix up different goals. Letting the user choose his own salt could even hurt security, because the user could choose a weak salt, which is not unique or is too short.
Asking for a user defined salt is just like asking for a second password, you wouldn't do that, would you? You could increase security this way, but then i would use the second password to encrypt (two-way) the calculated password-hash.
Better in my opinion is when you define a server side strong key, and use it to encrypt the password-hashes. Then the attacker cannot brute-force the hashes, until he gets additional privileges on the server to read the key.
Related
My database stores unique salts for every user.
I'm creating a login script in php for an application where each user has it's own unique salt and here's how I plan to implement the login.
User enters details and sends them
Username is sent and script check if it exists
If it does then returns the salt for that user otherwise general error is returned
I need the script to return the salt for that user because otherwise how would my app verify that the submitted password is correct when it cannot hash the password without the salt and send it back?
Now here's what I'm unsure about. Does it matter whether the salt is encrypted or not because a hacker could just see what it is and see the password hash and maybe could do something with it. Should I encrypt the salt before I send it?
Maybe I'm not understanding/overlooking something in the replies below.
Advice needed please.
It doesn't matter if your salts are hashed or left as plain strings - the important point is that salting a password prevents the direct use of dictionary/rainbow table attacks to brute-force crack passwords. An added advantage is that each user has a different hashed password as a result.
Salts are randomly generated string that are created server-side and don't involve any kind of transmission to or from the browser.
On your server:
// Password from form
$pw = $_GET['password'];
// Generate salt using unique values
$salt = (rand(8).$registration_date.$username);
// Password to be hashed
$pwthb = ($pw.$salt);
If a hacker gains access to your databases, then your game is over in the majority of cases as you need to store the initial random salt to hash it for comparison.
A simple example:
User enters initial password in browser upon registration
On your server, password is combined with a unique salt, hashed and stored as password in DB
Salt is stored in DB
Note: hashing can be done using PHP or using MySQL/DB functions
When the user returns:
User enters password in browser
Grab salt from DB and combine with the password entered
Hash password+salt and compare with stored/hashed password
If they match: authenticate
In terms of further reading, It's probably worth looking over the following:
Is encrypting a salt value with a password/plaintext a viable alternative to straight up hashing?
The necessity of hiding the salt for a hash
How store salt in distributed environment
A client has a huge userbase and I'm required to encrypt/hash passwords in a secure manner. The problem is I can't ask every user to change their password and the passwords are already hashed with md5() without a salt. One way of doing this is to encrypt the current passwords with a salt and when a user changes or resets the password i just encrypt it with the salt.
Are there any pitfalls or more or less obvious dangers of doing so [ i mean sha1(md5(password) with salt) ]?
Thank you for your time
Add a new field to the user table for storing the new securely hashed passwords - for this, please do something safe involving per-user salt and multiple rounds. Check what other people are doing (ie., bcrypt) instead of rolling your own.
When doing a password check, if the newPass field is null, use the old password lookup, but urge users to do a password reset once authenticated.
Modifying the current (old) password scheme to be hash(perUserSalt + existingPassWordHash) should work fine.
if you plan to use sha1(md5(password).$salt) it's all right.
You can use this system even further. No need to take any special action when user changes a password. Just encrypt it the same way: sha1(md5(new password).$salt)
It depends on what attack you are attempting to defend against. If the attack is someone viewing the database, then you could use a symmetric encryption method (like AES) with a key defined outside the database. Using this method requires the authentication procedure know the encryption key and you update all the rows in the database by encrypting the hashed password with the encryption key.
If the above is not an option, you have a problem. ;) The problem is that right now you don't know what any user's password actually is. All you have is the hashed version. Your routine for verifying a login is to take the input supplied by the user, hash it, and compare the computed hash with the stored hash.
Your option would be to store the old hash and create a new field to store the new algorithm. Then as people log into the system, perform the upgraded salted-hash and delete the old hash. This will work as you expect, but if a person never logs back in (or changes their password) they will never upgrade to the salted version of the hash.
My personal opinion is to use the AES encrypted option since that prevents the casual viewing of hashed passwords and it covers all the passwords in the database.
I have a classifieds website, where everybody may put ads of their products.
For each classified, the user has to enter a password (so that they can delete the classified whenever they wish).
So basically, when somebody wants to delete a classified, they click on the classified, click on the delete button, and enter the pass.
I use MySql as a database.
I use this code basically:
if ($pass==$row['poster_password'])
where row[poster_password] is fetched from MySql...
What do you think?
Thanks
See this: Secure hash and salt for PHP passwords
Hash their password (maybe with some salt) on the way into the database. Store their hashed password in the database (NOT their actual password). Then fetch their hashed password from the database and hash their input password and compare the hashed passwords.
Some lame pseudo code:
password_hash = hash(password_cleartext)
# store password_hash in database
Later:
input_password_hash = hash(input_password_cleartext)
fetched_password_hash_from_db = fetch(db, password_hash)
if (input_password_hash == fetched_password_hash_from_db) {
... authenticated ...
}
For a start with php, try: http://php.net/manual/en/function.sha1.php
Your code looks safe, but your design may need some work.
SQL Injection
The dangerous part of the code is in storing anything in the database, or showing anything to the users, that is collected from the user. So, the part you have to be careful with occurs prior to your example. Ensure that you're validating, filtering, and escaping any data that you collect from the user, including the password and the ad information.
Encryption
The advantage of storing the password in the database is that you can let the user retrieve the password via email or some other means if they lose it.
However, if you do store passwords, you should store them encrypted, using a secret key, so that if someone is able to direct read access to your database, they can't read all the passwords in plain text. Still, you're going to have to store the secret key somewhere, and if someone gets your secret key and has access to your database, they will have access to all of the passwords.
Hash Values (recommended)
It's best practice and more secure to only store one way hash values (SHA1 or SHA256) of the passwords in the database instead of the actual passwords. This way, you cannot retrieve the password. Hash values are intentionally one way by throwing away some of the data.
Instead of retrieving the original password, you hash the password that the user enters and compare the hash value against the stored hash value to see if it matches. If the user loses the password in this case, instead of emailing the password to the user, you email the user a new, randomly generated password.
Storing only the hash value protects your data even further, since even if the user has read access to your database, the hash values offer no advantage, and there is no secret key that will unlock all of your hash values.
When you hash the passwords, be sure to use a random salt value and store the salt to protect your list of hashes against rainbow attacks.
Summary
Sometimes you don't get to choose the password. Sometimes the password comes from another system, so you don't always have a choice, and sometimes your superiors (maybe even the users) will demand that they be able to retrieve passwords, however, when possible, you should choose the more secure option.
Note that all of this encryption and hash value business only partially protects your server against people who are able to obtain read only access to your data. Sometimes, getting your data is enough of a prize, so if the user can read the password hash, can they read your credit card numbers?
You need to protect your database. Do you have a secure password on your database system? Do you only allow local access to your data? Have you created a database user with least privileges to use in your application? Are you properly protecting yourself from SQL injection and scripting attacks?
If someone has read and write access to your data, the whole password business becomes moot.
Don't store the actual password in the database. Instead store a checksum (MD5, SHA1, etc). When you want to compare, perform a checksum of the value the user submits and compare the checksums.
That way you never have the actual password in memory.
Best practice is to keep a salted sha1 hash in the database:
if (sha1($pass.$row['poster_salt'])==$row['poster_password'])
(poster_salt is a random string generated and saved when the user chooses the password.)
That way if an attacker gets access to your database, they still won't get the passwords of the users (which are probably used elsewhere too - most people don't bother to choose different passwords for different sites).
Also, you should use secure (HTTPS) connection. And require sufficiently strong passwords.
(At least if you want good security, which might be an overkill in the case of a simple ad listing).
I would encrypt the password before storing it, then decrypt when retrieving it so you can check it against what the user entered in plaintext (per your example code above).
Also, protect yourself against any SQL injections, or someone could see all the passwords (and other data) in your database.
This implies the passwords are placed into your passwords unencrypted. If this is the case you should be using some sort of encryption when entering the passwords. One way of doing this is the MD5 function which hashes the password.
When doing the insert you would do
Insert into table(email, password, whatever) values('$email', md5($password), whatever)
And when comparing you would do
if (md5($pass) == $row['password'])
You should hash the password somehow and store and compare using the hashed version. See this link for more details:
http://phpsec.org/articles/2005/password-hashing.html
my suggestion is the following
the users table have two columns, one called "password" and the other "salt"
$password = 'youruserpassword in plain text';
$salt = bin2hex(openssl_random_pseudo_bytes(32));
$passtostore = hash_hmac('sha384', $password, $salt);
insert into users(password, salt) values($passtostore, $salt);
Then to verify if the user has entered the correct password...
retrive both password and salt from the database and
if(hash_hmac('sha384',$userpass, $row['salt']) === $row['password']) {
// is valid
}
I am using md5 to encrypt the passwords in my project.
When user clicks on forgot password and submits his email,I have to send His password to him.
But the password is encrypted using md5.Generating new password should not do.Because In this project admin can see all the details of the user. So i have to show the original password to Admin. So The initial password is very important. SO how can i decrypt the password or any other way to send him original password?
Thanks in advance...
Hashes are not designed to be decrypted, which is why they're often referred to as "one-way hashes" instead of just hashes.
Instead, either...
Generate a new password, hash that, store the new password hash in place of the old one, and email the newly generated password to the user.
Generate a new password, hash it, store it in a field for temporary passwords, and then when the user logs in with that password, prompt them to enter a permanent new password.
Generate a nonce, store it in a field for the nonce, and email the user a link with that nonce which will give them access to a page to enter a new password.
The third option is probably the best all around, since it doesn't leave an actual password (temporary or not) in plain view to someone reading the user's email, and since it utilizes a nonce, once it has been used it can't be used again by a malicious user.
The reason hashing is used for passwords is specifically to prevent them from being stored in a form where a malicious user could determine the password simply by looking at the database.
Edit:
"So i have to show the original password to Admin."
If you are hashing the password, this is not possible. In general, it is actually a bad idea to allow administrators to see users' passwords, because a large percentage of users tend to utilize the same password for multiple things, and the administrator of one thing (say, a company network) is probably not the administrator of many other things (say, a user's online banking system).
MD5 is not an encryption algorithm, it is a hashing algorithm. The two are not the same; encryption is designed to be reversible (hence the complementary term "decryption"), whereas hashing is designed to be one-way only.
You can't. The reason cryptographic hashes[1] are referred to as "non-reversible" is that they can't be reversed. Which is the entire point of using them for password storage - it means that, if a Bad Guy gets his hands on the password database, he can't just reverse the hash to find out what all the passwords are.
I see from your edit that your intent is to display the user's password to the admin user(s) rather than for password recovery by the user himself. This is a Very Bad Idea. Many users attempt to ease the burden of remembering passwords by using the same password for multiple systems, which means that displaying their password in your system has a high probability of compromising their accounts on other systems.
True story: Back in 2000, I took a job at a startup that produced voicemail systems. To introduce me to the product on my first day, the IT director had me create a voicemail account, which I did, then he brought it up in the admin interface. I just about died when I saw my voicemail PIN displayed on the screen for all to see. Partly because it was shockingly bad security practice, but mostly because, even though he didn't know it, he now knew the PIN for my ATM card. That's just bad, bad, bad all around. Don't do that.
[1] MD5 is a hashing algorithm, not an encryption algorithm. The key difference between the two is that, for any given hashing algorithm, there are an infinite number of inputs which will produce the same output (which is why it's not reversible), while encryption has a one-to-one correspondence of input to output.
If the password has been hashed then you'll probably have to create a random password and send that to the user. Then, once they've logged in, take them to the Change Password screen so they can change their password to something more memorable.
One particular purpose (among others) of a hash value is that it's irreversible, if it works perfectly.
The most common way for a "forgot password" functionality is, to generate a new password and tell your user to change it as soon as possible.
Just adding this as a sidenote:
While you cannot "unhash" the MD5 hash, you can look it up in a Rainbow table. That might allow you to send the original plaintext password to the user. I am not suggesting to do that though, because it's just a waste of resources compared to just creating a new password and sending that to the user instead.
From http://en.wikipedia.org/wiki/Rainbow_table:
A rainbow table is a lookup table offering a time-memory tradeoff used in recovering the plaintext password from a password hash generated by a hash function, often a cryptographic hash function. A common application is to make attacks against hashed passwords feasible. A salt is often employed with hashed passwords to make this attack more difficult, often infeasible.
Also see the comments below for additional notes.
I currently use,
base64_encode() to encode a user's password, this works well because it allows me to simply use base64decode() to decode the password to a word and send to there email if they lose there password.
I have been reading up on password though and a lot of people seem to say that you should use sha1() to encode a password. I am all for improving my system's security but if I convert to use shal() then I will not be able to send a user there lost password.
What do YOU use? Can you give me some advice? And is there a way to decod to a readable password to email a user?
As I typed this question I just remebered that some forums do not send you a password when requested but instead send a special link to re-set your password, I am guessing that this is because they are unable to decode your password maybe?
//what I use now
$password_encoded = base64_encode($password);
//what I am considering using
$password_encoded = sha1($password);
Please, please for the sake of your users do not store their passwords in any reversible format! It doesn't matter if it's Base64 encoded or triple-DES 168-bit encryption - if it is reversible, it is exactly as secure as if you didn't encode it at all.
No website that has any interest in protecting itself or its users (or has a lick of sense) will send a user their password via e-mail. The only thing we can do that's even remotely close to secure is to send users an email with a unique, one-time-use link that lets them set a new password.
Store a hash (bcrypt or PBKDF2) of the password which has been salted
Throw away the original password as soon as you've hashed it. Excise it from memory.
Always require the user to create their own new password over an SSL channel
Trying to get by with anything else is honestly just negligence. Let's use a very common scenario used in security discussions:
User Frederic's email is compromised. This could be from leaving his computer unlocked or using a weak password. Regardless, an unauthorized person has access to his messages. Ideally, this would mean nothing more than some embarrassing love letters read by a stranger. Unfortunately, the unauthorized person discovers a forum will email Frederic's password in plain-text. Like most users, Frederic uses the same password for everything, including his online banking. His username is listed in an email from his bank. Now the situation is very unfortunate.
Users are placing trust in you when they create a credentials-based relationship with you. Part of that trust is that you will keep those credentials as a secure secret between you and them.
Related
A lot of the surrounding issues and ideas have been answered very well on SO:
Difference between Hashing a Password and Encrypting it
Why is challenge-response approach a poor solution for forgotten passwords?
Non-random salt for password hashes
As an administrator, you never actually need to recall the password of a user. You simply need to know if a string they've once submitted, is identical to another.
If a user forgets their password, they don't need to be told their old password, you can simply have them provide a new one.
Since you don't need to know the actual passwords, using a crytographic hash of the words would seem like a safe way to store them. However, large tables of pre-computed strings have been made to easily do a reverse-lookup of the hash back it's original string. These are called rainbow tables.
To avoid easy lookup of pre-computed string, you should salt your passwords before hashing them. The salt can be their username prepended, or their user ID postfixed, whatever extra information you have on the user that is permanent that you can easily add to the password during authentication.
You should let a user RESET a password but never RETRIEVE their password. That is why you would want to use a one-way hash (SHA2) instead of a form of encryption that lets you decode it.
Imagine if you left your email open. I could simply request to retrieve your password for some website, delete the email, and you would never know. On the other hand, if you required me to reset the password instead, the account password would change and the owner would obviously realize that something is wrong. (This is a dumb scenario but the concept is what's important)
Hashes can be "reversed" by trying all possible combinations of words (or using rainbow tables) until a matching hash is produced. One way to avoid this is to append/prepend the provided password with a salt to make it a very long and unpredictable string. The salt should be a unique string of data unique to the individual's account.
In PHP there is no SHA2 functon. SHA-2 is a family of hash algorithms, (SHA-256, SHA-384, SHA-512, etc...)
hash('sha256', 'The quick brown fox jumped over the lazy dog.');
An absolute must-read on this topic is Jeff's own You're Probably Storing Passwords Incorrectly. Here's the executive summary:
Do not invent your own "clever" password storage scheme.
Never store passwords as plaintext.
Add a long, unique random salt to each password you store.
Use a cryptographically secure hash.
Base64Encode offer no security, because anybody can reverse it easily.
If you absolutely need to reverse the password, a good way is to use a secret question, and to use the answer as an encryption key. Once the password is encrypted, you throw the answer away (you do not store it). You also use the standard sha1 encryption for the time when you need to verify that he enter the right password. If the user want its password, he enter the answer to its secret question, and you use that to restore the password and send it back to him.
It's not as secure as hash based encryption only, but if you need to send back the password it's a good compromise.
You may want to look at the mcrypt library for php http://ca3.php.net/mcrypt
I always delete my account only any sites that emails me my password. I put too much effort and time into memorizing long random passwords to have it sent to me in plain text.
Use sha1() or higher non-reversible hash to identify the password. When authenticating a user password, retrieve the hash, and compare it with the hash of the password supplied during authentication. If they match, then the user is authentic within reasonable standards.
$user = "joe";
$password = 'password';
$saved_hash = DB::Query("select hash from users where username = ".quote($user)." LIMIT 1");
if (sha256($password) == $saved_hash) User::authenticated();
Never, ever send passwords in email. Send a unique, non-predictable, generated key, such as in PHP:
$key = sha256(time().rand().$secret_seed);
Send this key to the client, for one time use, to set a new password.
You will want to use a hash(preferably sha1) with "salt"
You can do the hashing on the server when authenticating in one quick query:
SELECT * FROM user WHERE password = MD5(CONCAT(?, salt));