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.
Related
When a user wants to do a password reset, an email is sent with an unique URL so he can reset it. Like this:
website.com/forgot.php?email'.$email.'&hash='.$thehash
$thehash is a unique hash for every user stored in the database.
The problem is that $thehash is stored in the database just the way it´s used in the URL. That´s just as stupid as storing the passwords in plain text. If someone get´s access to the database it doesn't matter that I have my passwords stored with sha512 and a secure salt, the attacker can just get access to all account using the values (email and hash) all found in the database and change passwords for users.
When I hashed user passwords the user had one part of information that could not be found in the database, the plaintext password so it worked out. But now, I have no idea what to do since I have nothing unique not found in the database. So what is a good way solve this? How do I securely store hashes?
The problem isn't with how you're storing hashes, it's with how the reset link works.
You don't want to use the hash to authenticate a user for password resets, for the reasons you mentioned.
Use a perishable token instead. Whenever a user requests a password reset, generate a token (256-bit should be enough) and store its hash in your database, along with the user who requested it, and the token creation datetime. Put that token in the reset link (instead of the email+hash). When the user clicks the link, your server will receive the token, find the corresponding user and it'll be safe to change the password.
By only storing the token's hash in your database, but using the unhashed token in the email link, you're making sure that even if the attacker still has access to your database, he won't be able to forge his own reset links.
By comparing the time when the user clicked the link with the datetime stored when the token was generated, you'll be able to control how long the reset link is valid (and avoid situations where a user forgets to delete the email, gets his email account compromised, and have the attacker use the reset link).
Check this Authlogic Password Reset Tutorial for a full implementation.
When a user wants to do a password reset...
I will refer you to the OWASP Forgot Password Cheat Sheet, which in essence states:
1 Gather Identity Data or Security Questions
2 Verify Security Questions
And an alternate to giving the users a hash of something:
3 Send a Token Over a Side-Channel: "After step 2, lock out the user's account immediately. Then email or SMS the user a randomly-generated code having 8 or more characters... It is also a good idea to have the random code which your system generates to only have a limited validity period, say no more than 20 minutes or so... Of course, by all means, once a user's password has been reset, the randomly-generated token should no longer be valid..."
Allow me to add here that you can email the user the original token, but store a hash of it in the database using exactly the same protections you use for normal passwords, i.e PBKDF2/BCrypt/SCrypt, and storing only the resultant hash in the database. Then when the user uses the password reset email, if it's still within the very short time window, take whatever they give you, and use your password_verify() function to compare it to the reset token hash.
4 Allow user to change password
Thus, your reset tokens are protected by:
Only being issued upon a validated request
Only being valid for a few minutes
i.e. hopefully too short a time for someone who's stealing your database backups to be able to use them!
Optionally being protected from rogue database access by your password hashing mechanism, just like any other password.
Your reset tokens are obviously not protected from an attacker with access to the user's email account, or who can change the listed email account, while the token is active.
Password reset via security questions as a whole is obviously not protected from an attacker who knows or can compromise the security answers and who has access to (or who can change) the user's listed email account.
#relentless is correct. If the attacked gains access to the database isn't it true that he/she would be able to reset the passwords regardless of whether they had the keys? You're also assuming they've either gained access to the user's e-mail account or guessed the hash entirely. Another thing to consider, you don't necessarily have to store the hashes in the database. Consider this: let's say the hash is created by combining the user's e-mail with a key you've previously determined. When the reset page loads simply rehash the e-mail and key and see if it matches the hash in the query string.
Why don't you pass $thehash as a session variable, then check it to the function your directed to 'if it is set?', if it is, then execute, after then delete the session variable.
How do I securely store hashes?
...
So what is a good way solve this? How do I securely store hashes?
This is the "Unattended Key Storage" problem, and its a problem without a solution. See Peter Gutmann Engineering Security.
John Steven of OWASP provides one of the better write ups related to password hashing and storage. He takes you through the various threats and explains why things are done a certain way. See
Password Storage Cheat Sheet
Secure Password Storage Threat Model
There are multiple posts on the Internet regarding this issue, but here's how I see it.
(Do correct me if I'm wrong in what follows...)
A hacker can only do permanent damage if your actual DB and login credentials get known/compromised, where the data can be changed. Otherwise, the data remains safe even by changing the email address in the URL. Just as long as you don't give a potential hacker a back door to change the Email address; that's gold in its own right.
If passwords are properly stored using a one-way irreversible hashing method, then they are just that; irreversible and chances are rather great that they cannot be put back together. If a user's password has been compromised, then that will be a red flag for you to re-think the way you're using your DB.
At best, even if a user's password gets changed, give the user a method to change it again, then set a column to track how many times it has been changed. If it keeps changing too often, then again that will be another red flag. I have used a similar method to what you're using now and nothing got changed in the DB even when changing the Email address in the URL; everything must match.
Plus, even if someone did change a user's password, depending on what type of permissions or access you've given your users, what's the hacker going to do, change the password again?
The URL should contain the Email associated with the account, the hashed key stored in the DB and then retrieved, and will only work if a hacker has gotten hold of the user's Email account credentials and has gotten access to what should be a unique link.
I don't know which hashing method you're presently using, but there are a few that many suggest using.
crypt()
bcrypt()
scrypt()
PBKDF2
PBKDF2 on PHP.net
PHP 5.5's password_hash() function.
Other links:
PBKDF2 For PHP
Footnotes:
Quoting owlstead if I may: (which I do agree with)
"The best methods are PBKDF's such as PBKDF2, bcrypt and scrypt. crypt should not be used if possible, password_hash() is an implementation of crypt and bcrypt and not a separate algorithm. Users passwords can always be compromised if they choose a bad password. One way cryptographic hashes or PBKDF's cannot be reversed, but they can be brute forced (e.g. using a dictionary attack)"
I am training to secure the login process.
I have used sha 256 in the sign_up.php:
$username= check_input($_POST['username']);
$password= check_input($_POST['password']);
//the password is encrypted in sha256
$secure_sign_up_password = hash('sha256', $password);
and then of course in my users table in my SQL database, I can read:
in the column 'login' the actual typed login
example: if somebody type 'michael', I will see 'Michael' in the SQL database
in the column 'password' the actual typed login
example: if somebody type 'fruit', I will see the hashed value like 'e8bfab56c53980cd014206c8da2f8c9b9708eaacc61' in the SQL database
My question is simple but maybe a bit naive (I'm a newbie): I thought that I could still be able to read the actual password somewhere in my database and that hashing was only made to protect the password from getting intercepted and read while it was being sent. I never know, somebody might ask me to send him his real password. But the only thing I can see is the 'hashed' one in the password column.
Is it made to be like this?
Is it possible to visualize also the real password?
If you would be able to "decode" those passwords, it wouldn't be a very safe system. Once someone gained access to your database - they would be able to gain access to every ones passwords without them knowing...
If you have ever forgotten a password for a site (and we all have - don't deny it!), you'll recall that they usually* don't simply send you your password (in plain text) as a reminder to your email - they'll give you the opportunity to reset it. This way (verifying usually through your email/phone number) they'll know that you are indeed the person who opened the account.
* If they send you your password in plain text that probably means they are storing it like that or in some other easily decrypted form. This site is most likely not as secure as they would like to think...
If you are interested in leaving yourself a "backdoor" of sorts to be able to access any of your users accounts, what you might think of doing is having a special login form from inside your administrator account, that allows you to use the encoded password to log in. That means that you simply leave out the hash('sha256', $password) and pass the $password already encoded (which you extract from your database). It's a bit hacky, and if you already have an administrator account then there wouldn't be much use to be able to log in as a different user because you are already all powerful!
This is by design. Nobody should know what my password is, except for me. Even you as a (insert fancy title here) should not know my password. If I forget it, that's my problem, but your site should offer me a way to reset it. Then when I reset, your site should store the hash once again. The plain-text password should never be stored anywhere.
Never never never hold password in open format in database. If someone find exploit in system, he will be able to make any sql query and get users passwords. And hacker will be able to login into system as user, because he knows username and password
If user want restore password, make functionality for regenerating password. Never store password in plain text.
SHA256 is hash function. Mathematically it means - data can be "hashed" only in one way. I mean, that from hash you cannot restore data. You can read this http://en.wikipedia.org/wiki/Hash_function about hash functions and this about http://en.wikipedia.org/wiki/Sha256 sha256
Result: If someone crack you database and get username and password, he is unable to login into system. Because hacker have only hash data and can't get exactly password for login.
As i mentioned before, hash function can be "hash" data only in one way. But some hackers build VERY big data massive for some predefined algorithms. I mean, that they build hash tables for passwords. Such hash tables looks something like this:
password hash
------------------
a some_hash1
b some_hash2
... .....
qwerty some_hash3
some_data some_hash3 -- yes, data can have collisions. See wiki about hash functions
And if hacker hacked you database and have such table, he able to restore password. For example, hacker get for admin user hash "some_hash3", then hacker search such hash in hash table, find that hash "some_hash3" have password "qwerty" and "some_data" and hacker will try to login with such passwords.
Result: Use salt. For nowadays hackers have such tables for 6 symbols passwords. But you can "suck" them in very simple technic: When you store password in database, add to password some value (salt) and get from such value hash:
// somewhere in code, where creating/updating users password
$password = hash('sha256', $salt.$password);
and when you will check password, use the same logic
Thanks
sha256 hashes and other hashes are one way. See http://en.wikipedia.org/wiki/Cryptographic_hash_function. If you want to be able to decrypt what you write in the password fields in your database, you might want to use another approach.
Instead of creating a hash, you could encrypt with a key, that you do not share with your users. Look at http://www.php.net/manual/en/book.mcrypt.php. The key would be part of your code though, as it's symmetric encryption.
To do it really safe, try real PKI encryption (encrypt with a public key, decrypt with a private one). Look at php.net/manual/en/function.gnupg-encrypt.php or php.net/manual/en/book.openssl.php.
But as other here have said, such things are reasonably NOT done ;)
For user's password entered in a form before post, I simply just do
<?php
$pass=crypt($_POST['memberpwd']);
?>
But how can I later get the plaintext of that password in case the user may request ? Thank you.
EDIT: I found How can I encrypt password data in a database using PHP? and http://www.securityfocus.com/blogs/262, but I would just want to learn about this at a more basic level to understand the ways as to how it actually works.
Always store a password in a database using only a hash of (the pasword and a randomly generated salt) (googling for these terms combined with PHP should yield some useful results).
You never restore a plaintext version of the password, you provide means for the user to choose a new password after the user clicks on a unique referral url you only send out by email automatically on request.
(Very basic security).
EDIT:
I'll explain why you need the salt. Suppose someone compromised your database and has the user table with simple (e.g. MD5) password hashes. He (or she) can now simply launch a dictionary attack against the whole table with simple password combinations (e.g. select * from users where pw_hash = ...). If you use a randomly generated (but stored) salt to be used in the hashing of the password, this brute forcing attack gets exponentially harder to exploit.
The first thing to understand is exactly what crypt() does. Start off by reading this: http://php.net/manual/en/function.crypt.php
Essentially, crypt() is a hashing function. To be more exact, it is a one-way hashing function. As such you aren't going to be able to recover the password from it.
In today's world when a user has "forgotten" their password the best way of handling it is to create a new password, store that and email it to them.
By doing this you are ensuring that if they used the same password for multiple services you aren't inadvertently exposing those other services to nefarious people. Second, if it isn't the original user requesting the password, the next time they try to log in they'll notice their password doesn't work anymore.
Look at my answer to a related question.
Basically, you never ever ever store plaintext passwords. Databases can be compromised and most users use a universal password, which will allow the attacked to have access to tons of data. And it will be your fault (to some extent).
Hashing (in your case) works on this principle:
if hash(session.password) == database.hashed_password:
# You can safely assume session.password == database.password.
# Notice that I don't store database.password, but instead store:
#
# database.hashed_password = hash(register.password)
#
# when the user registers. That way nobody will ever know the password.
You can also use salts to make your hashes more secure. The same principle holds:
if hash(session.password + 'imasalt') == database.hashed_password_with_salt:
# Same as above.
Common practice is to use a one-way hash algorithm like SHA (and MD5 in the past). These cannot be reversed. If your user need to recover a password, the system usually resets it and tell the user the new password.
If you want two-way encryption (highly discouraged to store passwords) then your application will need to keep a secret (or have the user provide it).
Take a look at mcrypt http://php.net/manual/en/book.mcrypt.php
You don't. If they've forgotten their password, you should reset it and send them an email to create a new one, or something along those lines. Storing passwords in a way that means they can be decrypted and retrieved is very insecure and could, possibly, be illegal in some countries (I'm not a lawyer).
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 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));