So I am making a basic log-in page. I have a good idea of what to do, but I'm still unsure of some things.
I have a database full of students and a password column of course. I know I'm going to use md5 encryption in that column. The student enters their e-mail and student ID, and they get e-mailed a password if correct.
But, where do I create the password? Do I have to manually add the password (which is just a randomly generated string) in mySQL to all the students? And I am suppose to send the password to the student; how will I know what to send the student if the password is encrypted?
I was thinking about generating the password when the student first enters their e-mail and student ID. They get an e-mail of the random string, and at the same time, I add the same random string to the database, encrypted.
Is that how it's suppose to work though? And it feels unsafe doing that all on the same page.
Sorry for the long-winded, newbish question. I find this all facisnating at the same time as well (AES and RSA encryption :O)
A few things here:
You aren't really encrypting it, you're hashing it. Easy thing for newbies to confuse, but just wanted to get that out of the way.
Don't use MD5, it's just not a very secure hash. Use one of the SHA variants instead if possible.
Don't just hash the password, you'll want to "salt" it too. Basicly this involves adding a random string to the password before you hash it, and storing that random string somewhere where you can retrieve it later (so that you can validate the hash when the user enters their password). This helps prevent against pre-computed dictionary attacks.
As for generating the password, I think you are on the right track - I would just generate it when they create their account, email it to them, then hash it and store the hashed (and a random salt) on the user record in the DB.
If you're generating passwords, generate a password and send the generated password to the student. MD5 that password and store it in the database. When someone logs in, MD5 the password they submitted in the form and compare that hash to the one in the database. If they match, successful login.
Your PHP should generate the password at the time of registration. Email the password to the student then run it through a hashing function (md5() is ok but sha1() is better). Store the hash in the DB and drop the original password. That way not even you can see what it is.
When the user logs in, hash their typed password and compare it against the hash stored in the DB. If they match, the user typed the right password.
Adding to the previous answers, depending on the hashing method you choose, the process goes like this:
1.- It is good idea generating the password the first time the students enter their ID and email.
2.- When they submit their data you receive it and generate the password randomly using any hashing method of your choice and store it in your DB.
3.- When they want to log in you ask for their ID and password, use the hashing method on the entered password and compare it with the one that's stored.
4.- If they lose their password and the hashing method has no way to be undone or reversed, you need to implement a method to create a temporary link sent to the student's email to create a new password, for there's no way to retrieve the old one. If the hashing method can be reversed then there's no problem, just de-hash it and send it to the studen's email.
Hope this clarifies a bit the process :)
Related
I have a ticketing help desk and I want to edit my users' passwords. But the passwords are encrypted in database like this : $2a$08$IdljRhapMTPYzdB0l4t/AuHatF8imyNREH.yKtBZelmVJAi5Sa/c.
I want to change the password in my help desk user_edit.php file and enter password field like this: password#123 and the server automatically encrypt it.
That's quite an unsafe solution, you should instead think of updating password. If needed, first encrypt it and than compare to the elder one to know if the user haven't typed the same password, which is unsafe.
You will need to find and reuse the code of the system that has created those passwords, or encrypts user entry as part of login.
For security you should encrypt passwords "one way". For logins you take the plain text input of the password, encrypt that in the same way that the password was originally and compare the encrypted texts, to see whether they are the same.
Find and reuse this encryption to add a new password.to your user.
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.
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 ;)
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 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
}