I don't really know even what questions to ask here. My problem statement is simple: I need to store a password on the DB with a salt, validate an entered password against the stored password, and authenticate the password using a random challenge word whenever a user tries to log on. I am using php/javascript.
In trying to figure this out, the problem I am having is that if I pass up a challenge word in an html form, then hash the entered password with that word, I can authenticate the password on the server, but I can not separate the password from the challenge word so I can validate it against the salted password on the DB. If I send the password to the server in the clear or hash it without a challenge word, I can validate it but now I can not reliably authenticate it.
I think I need a 2 way algorithm of some sort so I can encrypt it with a key, and then authenticate the key while validating the password. How do I do it? or if it can't be done then what should I be doing?
Encrypting a password with client-side scripting is generally a bad idea. The proper way to do this is to use SSL.
Also, never store password in cleartext. If you must use a method like the one you describe above, hash the password twice: once for storing it in the database, another time for the two-way authentication.
To store a password, generate a random salt. Store HASH(password+salt) and salt. (Either the server or the client can do this computation.)
To perform an authentication, the server looks up the salt and HASH(password+salt). It then generates a random challenge and sends the salt and the challenge to the client.
On the client, prompt the user for the password. Compute: HASH( HASH(password+salt) + challenge). Send it to the server.
On the server, you already have HASH(password+salt) and you have challenge. So you can also compute: HASH( HASH(password+salt) + challenge). Compare this to what the client sent you. If they match, the password is correct.
Note that this is vulnerable to a MITM attack, so it should be used over a connection that is itself protected from a MITM, such as an SSL connection.
Related
I'm using data from another server (not my server) and I need to login to this server. So I need to know password for every user account. I need to send this password to the server through HTTP request (no problem). But the server expect unsecure password.
So if the password is '123456' I have to send POST request with data:
"username=user&password=123456"
I can not use md5 function because after it I am not able to get back the password so my question is how can I encode this password? Is exists some common PHP function for this? For example:
$securePassword = php_encode("123456", "mykey")
php_decode($securePassword, "mykey")
Because I just do not want to store to my database "123456"
Use mcrypt_encrypt() and mcrypt_decrypt() for more info SO POST
The point of a hash is that you can't un-encrypt it. To check if someone entered a correct password, hash what they typed in and compare it to the hash of their password in the database. If it matches, the password is right; otherwise, it's wrong. Also, as long as you use SSL and a decent hash algorithm, you should be secure.
If you have PHP >5.5, you can use the function password_hash. If you have a lower version that is bigger than PHP 5.3.7, you should use password compat.
What you are looking for is not how to secure the password but how to secure the transport of the password. You do this using Transport Layer Security, aka TLS aka SSL.
That said, transmitting a password in this fashion isn't really advised and a better mechanism should probably be devised. If you encrypt or hash the password and transmit the cipher text this offers no protection at all because an attacker would simply send cipher text just as you would.
You need to encrypt the data in transit. Get SSL setup on your site.
Have a look at below 2 functions
http://www.php.net/manual/en/function.mcrypt-encrypt.php and http://www.php.net/manual/en/function.mcrypt-decrypt.php.
There is a reason passwords are hashed instead of encrypted. You cannot decrypt a hash. Generally the convention is to do the following:
Create Password
Send the new password to the server
Hash the password
Store the hash in the database
Check Password
Send the password to the server
Hash the password
Check if the hash matches the hash stored in the database
For this you should use something like SHA256:
// check password
$hash = hash('sha256', $password);
$db_hash = db_get_password($username, ...);
if ($hash == $db_hash) {
// correct password
}
I need an old password (not hashed) for sending to user but doesn't see a good idea? I read the documentation and there is only a method where I can get a hashed password. What can I do for getting real password?
Password should never be recovered clean after they are hashed and most of the time it's not even possible. I definitely suggest you to provide a reset password link instead of providing the old one.
Hashed password with MD5, SHA1, SHA2, Blowfish and others are one way encrypted this means that you shouldn't be able to decrypt them therefore making them secure (the first ones aren't that secure actually, but that's off topic here).
You can't get the original password; that is the point of using a hash.
If the user needs a new password, then generate a one-time, short-lived, random string and email it to them as part of a URL. When they follow the link, prompt them for a new password.
See the OWASP Forgot Password Cheat Sheet for more advice on how to do this as securely as possible.
You can't recover old password (unhashed) because its not stored in database. Only its hash is stored. Hashed can't be decrypted (that is why its called hash) ORM uses this model to solve alot of security issues.
Sending raw Password is real BAD idea. If you still want to do it:
If you are generating a password yourself during registration (Then mail it to user and then save it)
If user are setting their password. You will have it as POST variable. While saving it to database, mail it too.
If user is using forgot password to recover their password. Then reset the password first (generate a new one and save it to database) and send it to user.
You can't. A hashed password in Kohana is most likely a password encrypted with one-way encryption. I mean you can't decrypt it and get it in clear text. You should not store your applications password in clear text to protect the user.
http://en.wikipedia.org/wiki/Cryptographic_hash_function
What you may do is to generate a new temporary password for the user and send it to the users email, but I think reset password link is the best solution.
Is there a way to use a hashed password with imap_open() function? I have to hide somehow that password even from myself. But cannot find a way to do that. The actual PHP script works on the Linux server. A few people have sudo rights there. So, they may see that password anyway.
Thanks in advance
Such a feature would defeat the very purpose of password hashing:
The standard password scheme is for the resource that requires authentication to store a hash of your password, and that you submit to it your plain password. If the hash of your password matches the stored hash, the authentication succeeds. The purpose of this is that the resource never needs to know your password, nor can anyone who breaks in discover which password you used.
Now you're asking that the user be allowed to hash her own password and submit the hash, and that the resource then just compare the submitted hash with the stored hash. But this would effectively turn the hash itself into a plain password which is stored verbatim! Anyone who gets access to the stored hashes would now have immediate access to the resource, thus utterly derailing the very purpose of only storing a hash of the password!
I have a small community website and I need to implement some sort of forgotten password function. I currently store the passwords in the DB, encrypted with MD5.
Is it possible to sort of 'decrypt' and send it to user via email or would I need to have a password reset page?
An MD5 hashed password is not reversible. (MD5 is hashing, and not really encrypting, so there's a subtle difference). And yes you'll definitely want to provide a password "reset" process (and not simply email the password).
To give you a high level workflow for secure password resets...
When user asks to reset their password, make them enter their email address
Don't indicate if that email address was valid or not (just tell them that an email was dispatched). This is open for debate as it lowers usability (i.e. I have no idea which email I registered with) but it offers less information to people trying to gather information on which emails are actually registered on your site.
Generate a token (maybe hash a timestamp with a salt) and store it into the database in the user's record.
Send an email to the user along with a link to your https reset page (token and email address in the url).
Use the token and email address to validate the user.
Let them choose a new password, replacing the old one.
Additionally, it's a good idea to expire those tokens after a certain time frame, usually 24 hours.
Optionally, record how many "forgot" attempts have happened, and perhaps implement more complex functionality if people are requesting a ton of emails.
Optionally, record (in a separate table) the IP address of the individual requesting the reset. Increment a count from that IP. If it ever reaches more than, say, 10... Ignore their future requests.
To give you a little more detail into hashing...
When you hash a value like a password using the md5() function in PHP, the final value is going to be the same for that password no matter which server you run it on. (So there's one difference we can see right away between hashing and encryption... There's no private/public key involved).
So this is where you'll see people mention a vulnerability to rainbow tables. A very basic explanation of a rainbow table is... You md5() hash a bunch of dictionary words (weak passwords) in order to get their md5() hashed values. Put those in a database table (rainbow table).
Now, if you compromise a web site's database, you can run the users' hashed passwords against your rainbow table to (in essence) "reverse" the hash back to a password. (You're not really "reversing" the hash... But you get the idea).
That's where "salting" your passwords is best practice. This means (again, very basic idea here) that you append a random value to the users' passwords before you hash it. Now, when the rainbow table is run against your database, it's not as easily "reversed" because the md5() hash of "password" is different than "password384746".
Here's a nice SO Q/A that should help. Secure hash and salt for PHP passwords
According to this post The definitive guide to forms based website authentication, for step 3. and 4., I'm not sure you should send the same token you are storing.
I guess you must send the token, then hash it and stored the hashed token in DB. Otherwise, if your database is compromised, one can have access to the reset password page.
To summarize :
$token = md5(microtime (TRUE)*100000);
$tokenToSendInMail = $token;
$tokenToStoreInDB = hash($token);
where hash is a hashing algorithm.
No, MD5 is irreversible. The point of hashing passwords is to make it so an attacker who gets access to your database can't access everyone's passwords.
That said, MD5 (particularly unsalted MD5) can generally be attacked using a rainbow table. For security, you're better off using bcrypt.
You cannot decrypt the password, and you shouldn't even consider sending a password to a user via plaintext. (That is the #1 way to make me never ever use a site again; it's a GIGANTIC security hole.) Provide a password reset page that is triggered from a link containing a time-associated key that is sent to the user's password recovery email; that's the current state of the art in password recovery.
The best thing for you to do is request people submit their email address when registering. Then if they forget, have a forgot password link which resets their password with a random value which is emailed to them so they can gain access and then change their password back to something more memorable. This way you don't need to compromise the security.
You could have a link which they just need to submit their username into, butfor better security you should have a question and answer or memorable word.
As Marcus Reed stated, in 2015/2016 if you have PHP version >=5.5 don't use MD5, password_hash() and password_verify() provide an easy and secure hashing for your password with the ability to provide a cost and automatically salts the hash.
I don't have the ability to vote or comment currently which is why I'm providing a definitive statement to avoid confusion.
MD5 is intended to be a one-way hash. You will need to have them reset their password.
Write a page that accepts the md5 and email address as a get paramaeter and looks in the db for the email and md5'd password. Following Jared Cobb notes, that should get you on the right path. i just added some examples as well
eg url to send http://yourdomain.com/resetpassword.php?code=md5codesentviaemail
$code = isset($_GET['code']) ? $_GET['code'] : '';
$email = isset($_GET['email']) ? $_GET['email'] : '';
$checkPw = '';
if(empty($code) || empty($email))
{
die();
}
$sqlQuery = 'SELECT * FROM users WHERE email = "'.$email.'";
//remember to check for sql injections
//then get the results as an array, i use a database class eg $user
if(!empty($user['password']))
{
$checkPw = md5($user['password']);
}else
{
die();
}
if($checkPw !== $code)
{
die();
}else
{
//display form for user to change password
}
this should be sufficient enough for you to know that the user is a valid user and change his password
Use php's built in password_verify and password_hash.
No you cannot decrypt it. that is the whole idea.
You would need to send them a temp password and for them to reset it.
You'll need to do a password reset page. There's no way in PHP to decrypt MD5.
MD5 is a one way function. You can't decrypt it. SO you need to have a password reset page.
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));