Why is "Forgotten Password" bad? - php

I came across this statement
Do not use "forgotten password"
functionality. But if you must, ensure
that you are only providing
information to the actual user, e.g.
by using an email address or challenge
question that the legitimate user
already provided in the past; do not
allow the current user to change this
identity information until the correct
password has been provided.
Can someone clarify why forgotten passwords are a risk? I plan to handle it by sending the user a link in their email to reset the password, but will not provide them with the old password (since it's hashed anyway), and will not ask them for the old password when resetting. Is there something risky about my approach?

Your approach is absolutely right, as long as you don't store the password.
Asking the security question is absolutely bad instead, as it's prone to be bypassed just by guessing an answer.
Just a little edit: although it may be difficult to catch all of them, you should try to disallow the usage of mailinator email accounts (or email addresses from similar services) because mailinator + forgot password = disaster.

If Charlie can read Alices e-mail, he can also gain access to all sites offering "lost password" functionality.

The most annoying technique would be the following: you click forgot password, are asked for you email and get your own password (which many user use for porn and their online banking ;)) back in plaintext instead of setting a new one.
I would just copy the big players methods, like paypal or google. I think they should now what they do. The most common case should be: forgot password - get a link to your email where you can set a new one or generate a random, secure one (which the user will change back to 1234 immediately).
As we are there already: never return something like "wrong password", as this implies that at least the username exists.

Sending the user a link in an email is actually in compliance with the guidance given.
What it advices against is the practice of allowing users to reset their password without having to have any additional knowledge, i.e. something like a button that will reset the password without forcing the user to click the link in their email. I'm not sure I ever saw such a system, but it is certainly a bad idea =).

Your approach sounds very safe to me :) Ofcourse it should be a one-time link!
Also the "succes" and "email address not found" message/page should be the same. And have an anonymous text.
Like:
"If your mail address is in our system we have send you an email"
In this way, someone will be unable to determine if the email address is in your system or not!

As long as you send the link to the e-mail you have stored on the system then you should be OK - and it's what I'd expect from a system.
I'd also send a confirmation "you have updated your password" to the same address.
Additionally, if the user changes their e-mail address you could consider sending an e-mail to the old address stating that it's been changed to the new one. Slightly annoying perhaps, but it would provide an extra point at which someone could spot if their account has been compromised.

It's rather a sweeping statement and only a bad idea if you don't understand the risks involved and are sure that there is a net benefit (as with most things in life).
You should never store passwords in a recoverable form. Even allowing the customer to store a hint on your system puts the customer at risk. Passwords must always be stored using non-reversible mechanism - i.e. a hash. Given that is the case, you can't recover the customer's old password and send it to them.
Resetting the password on-demand to a random value, then emailing that value to the customer presents the opportunity to carry out denial of service attacks against individual logins (also the case when you disable an account after a number of failed login attempts).
That only leaves the option of generating an alternate login for the customer and emailing it to them - and flagging the account to force the customer to select a new password at next login.
All these approaches delegate the security of the customer account to the customers email system (and all the other email and network components between your server and the customer's inbox) which can, at best be very leaky - certainly its not anything you can provide any guarantees of security over unless you control all of the infrastructure.
C.

Related

Secure way to allow users to log in with a single unique code (no username)?

I am creating a website whereby users are given an account by invitation only, and are sent a unique code by post. Users can then log in (at least the first time) by entering the code only.
The goal of this is for it to be extremely easy to understand and use by non tech-savvy people.
User accounts will contain name, email, maybe address if the user wants to add it. No other sensitive information.
The site itself would not be of interest to anyone other than those invited, and will not be indexed by search engines.
If you imagine the users are receiving a piece of mail in the post which says something along the lines of:
Please visit www.example.com
Log in with your unique code:
A6XH3
As for the code, it must be extremely easy to remember and enter.
I was planning four or five upper case alphanumeric characters - e.g. A6XH3 - because I don't want anyone to have to enter a long hash or complicated string. I think 6 characters is the limit that I would deem acceptable for people to enter in this format.
An alternative idea I had was to use two/three easy to spell words, such as [adjective] [noun] which would be more fun and seem less "techy" to the users - e.g. pretty blue flower - which would be more in keeping with the spirit of the site.
Caveat
Website administrators must be able to see all the users' codes in plain text, so they can mail them out in the first place and/or offer support to anyone unable to log in. They may also need to generate a new code for some reason, and tell the person directly.
Is there any alternative to storing the codes as plain text in the database?
Questions
Is this secure enough for the context? i.e. The only people who know about the site are those invited, and there is no real motive for anyone else to try to force their way in.
Would you use either of my methods of unique code generation, and if not what would you suggest as a better solution?
Is there another way I could allow a simple login without compromising security or simplicity of use without a username?
Reminder
There is NO registration process and users don't choose their own code. Their account is created by the website administrator, and the site randomly generates a unique code for them.
Is this secure enough for the context? i.e. The only people who know about the site are those invited, and there is no real motive for anyone else to try to force their way in.
Not really, as it would allow an attacker (disregard the notion of 'no motive to force their way in') to brute force a login - just like any other login system, apart from in this instance you'd only have to try four or five upper case alphanumeric characters and not an e-mail and a password that adheres to various character sets.
Of course, you could do the following to help prevent a brute-force;
Add a captcha to fill on every login request
Two-factor authentication via SMS or E-Mail.
Would you use either of my methods of unique code generation, and if not what would you suggest as a better solution?
Both methods are fine in my opinion, as it's just like a site not enforcing "strong" password character sets. However, the reason for the code to be in plain text is no different than storing passwords (in the conventional sense) in plain text - you just don't.
Generate the random code
Send it to the user (securely)
Encrypt the code and store in the database
Is there another way I could allow a simple login without compromising security or simplicity of use without a username?
Simplicity is a relative term as it depends on your users. I would strongly recommended adding two-factor authentication via SMS or e-mail as outlined to my answer to your first question.
You could also use social media APIs to login. You'd then be giving the security to the social media platform and the user (without holding all the security concerns on your end, to some degree).
To raise points in your question that weren't explicitly defined as a question.
Website administrators must be able to see all the users' codes in plain text, so they can mail them out in the first place and/or offer support to anyone unable to log in
No. I see no reason why you'd need any human interaction, nor have a site administrator to see the passcodes in plain text - anything your administrators can see, a hacker can see.
When a user is unable to login, they should verify their identity via e-mail or SMS or security questions (or all three?), and have a new code generated for them via the system and sent to the user. The new passcode should be immediately encrypted and saved into your database.
User accounts will contain name, email, maybe address if the user wants to add it. No other sensitive information.
Any data that can be used to identify someone (for example their name, email and address) is considered sensitive.
Ultimately, no. Authenticating with a single piece of information is dangerous. I touched on this subject when I covered securely implementing "remember me" checkboxes. Your database lookups are going to leak timing information and allow attackers to trivially guess a valid code. (And implementing constant-time search algorithms is not a good idea.)
Having an authentication mechanism based solely on one value is a very bad idea. Always have two inputs: one for database lookups, the other for constant-time validation.
In most authentication systems, the username is used for the database lookup:
$userData = $pgsql->dbQuery("SELECT * FROM accounts WHERE username = ?", array(
$_POST['username']
));
...and the password is, ideally, compared outside of the DB query:
if(\password_verify($_POST['password'], $userData[0]['passwordhash'])) {
/* good password */
}
Aside from timing leaks (which may lead to timing attacks), having only one factor means that you can't benefit from a per-user salt without evaluating every single user in your database (which would be an enormous performance drag with a sufficiently large number of users).
With these requirements, you have to do something like:
$result = $pgsql->dbQuery("SELECT * FROM accounts WHERE password = ?", array(
hash($algo, $_POST['password'])
));
...which goes completely against best practices.
My advice: Bite the bullet and either use two pieces of information (an identifier and an authenticator), or eschew authentication completely and work with OAuth, OpenID, SQRL, Mozilla Personas, etc. Feel free to implement this if you really want to, but it will not be secure.
There are many good ways of doing this, if you don't want to change the unique code. You could use API's for IP location and then you could create like a pattern of the places where the user has logged in from and then once you have enough data of the location, IP, maybe user agent? or even ISP you could use an algorithm to determine any alterations in pattern you collected, and then block that user account temporary till he/she confirms it was them using the account?
This is just an idea, its kind of complex and probably to extreme for some people, but that's what I would try to do if I just waned a login system based on a unique key.
You can do it the same way, as you would do a with a password-reset page:
Let the user register with his email.
Send a link with a token to the user, a hash of the token is stored in the database.
If the user clicks the link and if the token is valid, welcome him and let him enter his own password.
If you send the user a link with a token, (s)he can simply click this link and does not have to enter a code anywhere. The token can then be a strong token like:
http://www.example.com/register/8eM2WwsuR59MnmyswYoQ
In the database you should store only a hash of this token, though if the token is strong, the hash can be unsalted and the algorithm can be fast like SHA256. When you implement it this way, you also have the password-reset for free.

Is there anyway to send someone a password that they can use but cannot see?

Just trying to hack together a simple script, and I had a little question about passwords.
Is there anyway I can send someone a random password that they cannot see themselves but can use to say, change their facebook password to in order to block themselves from logging in? I will then send them the visible password at a specified time later on.
This is for purely educational purposes, as I'm just building little apps here and there to learn php and mysql.
Example: Friend wants to get off facebook for 3 hours. He uses web app and I email him a randomly generated password for him to change his current FB password to. However, on the email it is hidden to him. After 3 hours, he gets another email allowing him to use it.
I understand there might be some easier ways / clearer methods of achieving my end goal, but I am just curious about this itself!
Thanks so much
If you are sending an e-mail that contains "something" that allows the user to log in with, you are sending them a password and if it's clickable/copyable from the e-mail, they will see it. Regardless of if the password is plain text that directly matches a stored value (like "thi$ismyPa$$word") or some other encrypted value that when inputted is decrypted to match a stored value is irrelevant, the user either way knows what that value is (because they have to enter it). In order for the user to provide a value, they have to have the value. As others have mentioned, you could implement a one-time use password into your application, but that wouldn't work for a facebook implementation because it's not your app and you can't control it's functionality. The short answer, if you provide something to the user (like an e-mail) that is used to access a system, then they can see the value(s) necessary to login.
The traditional approach is to calculate a hash sum of some kind from the password, and send that. Thre are one-way algorithms, like MD5, that can do this. That way, conformance TO the password can be assured, without having to send the password itself, or from which the password can be inferred.
For even greater security, both a hash and a checksum can be sent: that way the hash itself cannot be intercepted and sent as a proxy for the password: authentication will not happen unless both the hash and the checksum values agree.

Emailing password on sign up

Is it a horrible idea to email users their password on sign up - before it's hashed by the server side code and stored into the DB?
If it's user-entered, yes, it's a bad idea. E-mail is unencrypted and can be intercepted in transit between your mail server and theirs, as well as potentially being readable by folks with access to the two servers.
If it's a one-time temporary password, the risk is smaller, as they should change it shortly afterwards.
I'd email them a temp password, then require them to change in upon first login. Granted someone could change it before the user got the chance.
Part of the answer depends on how secure you think your credentials need to be. If you're a bank or any other site that deals with PII, then it's absolutely a terrible idea. But if you don't think there's a real payoff in cracking your site, then you can use your own discretion. It's definitely not a good idea from a security standpoint, but if there are organizational factors such as budget or legacy code that may drive you into such a corner, then you can consider it.
Also, I agree wholeheartedly with the other folks who answered suggesting not to send a user their password if they've picked it. That's an unnecessary potential security hole!
Better not, because if users specify an incorrect email address, other people can login using their information.
Also, you can make it more secure by not allowing to reset your password if you didn't login at least one time with the password that was used for the registration.
My opinion is this.
Option 1 - if user picks his password, don't mail it.
Option 2 - if you generate a password, send to user, have a link to active his account and change password.
Depends for what users get registered, each option can be used.

Activation on site

I have been running my website for a few months now and occasionally I find my activation isnt great. After the user signs up, they will receive an email which has an activation link provided.
I have a few problems and want to improve this if possible.
Firstly, the email sometimes doesnt arrive? Any reason for this?
How can I stop it going into the junk mail?
Secondly, at the moment, the activation is their username and an md5 of their username.
Is there a better way to do activations?
I'm always looking to improve and find better ways of doing things!
Thanks for your time.
Email doesn't arrive
First at all, you cannot really rely on mail. Never. Because you can't even know if it was received or read. A mail may be blocked as spam on server side, can be filtered on client side, or can just be lost or ignored.
There may be plenty of causes. For example, you may use e-mail authentication mechanisms. You may also start to check if there is reverse DNS for your domain.
Further, you may want to read some documentation and books to know how spam filters work. It will show you some obvious methods to reduce filtering of your mails, like sending mails in plain text instead of full-HTML, but also less obvious stuff like the words to use, etc.
If you have no choice and you must send mail, probably the most easy solution to prevent spam filtering would be to ask the users to add your domain to the list of safe senders. In practice, nobody will do it for you.
Activation through MD5
There is obviously a better way, since the one you implemented does not provide anything. If the activation is a hash from user name, you can as well just tell the users to calculate the hash themselves (thus avoiding all the problems with mails filtered as spam).
Normally, the users may not know what their activation code would be. It means that the activation code must be random or difficult to guess.
Generate a set of random characters, save them to database and send the code by mail. Then you would just need to validate the code against the one you keep in your database.
Some emails will always end up in the trash folder. It's probably best to put up a notice so that people know to check there, and make it possible for the user to re-request the activation email.
Using the MD5 hash of the username is not a very good idea because anyone can automate that. At the very least add some salt before hashing it, or even better, use a completely unrelated random token saved in your database.
For your second question, you may want to generate a random activation code and store it in a database. When the user clicks the activation link you could verify the code in the database using their e-mail address. This way a malicious user will have a more difficult time automating registration on your site.
$code = md5(uniqid(rand(), true));
If you're on a shared server, services like Yahoo are apt to label you spam. They want you to have a dedicated IP. It's almost impossible to get users to check the 1000 messages in their spam folders for your one activation message.
The MD5 hash is fine if you're hashing with a timestamp.
Keep this implementation, but supplement it with OpenID. That will take care of your Gmail and Yahoo users.
Yes, that's wrong. You shouldn't use MD5 for that.
The most popular way of do it is generating a rand code and saving it in the users table in the DB and send it by email as a GET parameter of the link.
About the emails, I would tell users to look in theit junk folders.
First problem: Make sure your mail isn't spammy. Follow the default guidelines for setting up mail... things like making sure you've got your SPF records configured, your mail is well-formatted, doesn't include spammy words. I generally test against Gmail, Hotmail and a server running SpamAssassin to check mails I send out; examine the headers to see if you're triggering any serious anti-spam rules.
Second problem: You'll want to make sure that the user cannot guess what his activation key is (thus removing the need for receiving the email). An MD5 of the username is insufficient for this. However, if you salt the MD5 you can easily prevent people from generating the MD5's in an automated way (that's an open invitation for automated signups). Adding Salt refers to adding a large amount of pregenerated random data to your input before hashing it. That way, the attacker can't lookup the hash in a 'rainbow table', as he no longer knows what the input for your hash was. Of course, you could just as well use a randomly generated string, which would probably be easier.
Another look on user registration. Let yourself inspire at stackoverflow and use OpenId and you don't have to care about user registration.
Update
You don't need to validate OpenId user via email. A user which signed up via Google or MyOpenId account is valid.
You don't have to care about questions if user is a bot? This servers did it already.
I have never got verification email from stackoverflow.
Mail arriving in the junk folder is a perpetual problem. The range of 'not looking like spam' strategies are numerous. Beyond the Junk folder I think that the overwhelming majority of reported 'not received' situations are actually just delays in propagating the email.
I'm currently implementing a resend for the activation email confirmation despite the fact that it should only actually be necessary in cases where the user has accidentally deleted the email and purged their trash or a transient error has discarded the mail. These cases are going to be rare but do exist so needed to be coded for.
I think the most important reason for implementing the resend of the activation confirm is customer service. It provides the user with an action that they can take while waiting for their mail and in the course of doing so and re-checking their email the activation email will eventually appear.
I wouldn't use the md5 as it creates too predictable a result. You want something that has a random or at least less predictable element. It is then problematic if you are invalidating the hash/token in the original email by resending a new mail so I would avoid overwriting the existing token and would instead re-use the same token which you should have stored or better stored the values from which it can be validated. This does constrain how you create the token as you want to be able to recreate it in the later resend mails or at least to be able to continue to validate all the inflight mails as valid. I am using a session aging model to resend the same token if that token is still valid. There is no reason why the user shouldn't see it as the same token and hence understand that they are all valid. In the case of an expired session/token a new one needs to be generated.
It's good practice to expire the activation mail token in case the mailbox falls into the wrong hands weeks or months later and the old mail is found. Assuming this can have some undesirable effect on the state of the users account at that later point.

Resetting passwords without emailing the user

We need to provide a way to reset password for users who are using our website. The typical way is to send email to the user and ask to click on the link to reset.
The issue is that we don't want to run a mail server just for the purpose of resetting password. Is there other clever way of reseting password without having to mail the user?
EDIT: This is for users who forgot their passwords.
You need some way to validate the user's identity to prevent other people resetting the password. Perhaps you could get them to set up some questions (like mother's maiden name, favourite colour) when they sign up. They can only reset their password if they correctly answer the questions.
You can immediately expire their current password and require them to change it next time they login. A couple of password reset systems do this.
EDIT: Since this is for users that forgot their password rather than a forced change, you should just take them directly to the link you would have emailed them anyway when they forgot their password. Make them enter an e-mail address they registered with and some other data you can validate with. Basically, what the other answers said.
I had this same issue with a very odd and demanding client. The site was a company intranet, that could be accessed via a VPN for telecommuters. One of the requirements (it was written in bold):
Password re-set mechanism should be convenient and not rely on e-mail. Re-set requests must be granted conveniently and require evidence that the site trusted the visitor prior to the re-set request
What I ended up doing was generating a Manderbolt (100x100) for the user to download as their 're-set' token, along with some secret questions that they would have to answer. To change their password, they would have to answer their questions and upload their fractal (the quadratic plane was defined based on their private information with simple hashing to avoid collisions).
This satisfied a requirement that password re-sets had to be based on what they had as well as what they knew. If they lost the fractal or forgot the answers to their secret questions, they had to appear in person to have the password re-set.
Not exactly bullet proof, but it satisfied the needs at the time. The challenge was making the fractals unique (at least 30 pixels unique), since most users shared a lot of common private data (city, state, area code, etc).
Edit
The fractal (rather, a one way representation of it) was used elsewhere as well. Think RFID + camera.
You could use standard mail to send new password :-).
Generally you need to verify that user which is trying to reset the password is the one who was originally registered. The easiest way is to send password reset link to email used on registration. Alternatively you can have some kind of security question, which will allow to reset the password, but most people will choose something really lame and you end up with server where it is quite easy to steal identities.
There must be some class that comunicates directly with remote SMTP server (e.g., ISP's SMTP server) by using sockets - just find such class and you won't have to run private SMTP server to send e-mails.
Use OpenID. Then it becomes the problem of an OpenID service provider to recover your users' passwords. And your users will be thankful for they don't need to remember yet another stinky password.
The usual answer to this would be some form of security question. If you don't have some barrier for the user to cross, you open the system up to allow almost anyone to reset the password.

Categories