Question

When a user forgets his password, you shouldn't send it by email. In his Pluralsight course "Hack Yourself First: How to go on the Cyber-Offense", Troy Hunt states that "there is no implicit transport-layer security on SMTP". This answer on Information Security Stack Exchange confirms that it's a bad idea to send or store passwords in the clear (including by email).

The proper way to reset a password, it seems, is to not reset it immediately. Instead, send the user a time-limited activation link via email. This requires manual intervention of the user and also does not communicate the password via email at any stage.

The aforementioned Information Security answer describes how one might implement a password-reset mechanism:

Don't RESET user's passwords no matter what - 'reset' passwords are harder for the user to remember, which means he/she MUST either change it OR write it down - say, on a bright yellow Post-It on the edge of his monitor. Instead, just let users pick a new one right away - which is what they want to do anyway.

If a user forgets their password, send them a secure one-time reset link, using a randomly generated reset token stored in the database. The token must be unique and secret, so hash the token in the database and compare it when the link is used.

The definitive guide to form based website authentication describes the implementation similarly:

Always hash the lost password code/token in the database. AGAIN, this code is another example of a Password Equivalent, so it MUST be hashed in case an attacker got his hands on your database. When a lost password code is requested, send the plaintext code to the user's email address, then hash it, save the hash in your database -- and throw away the original. Just like a password or a persistent login token.

But how will the user actually know the new password. Is it reset to some default? Is it changed to a randomly-generated password that needs to be communicated with the user somehow?

In "Hack Yourself First: How to go on the Cyber-Offense", the activation link takes you to a form where you can enter your new password.

That might be okay if you're dealing with a website, where you can go in and interact with the web application and choose your own new password. But with something like the .NET Web API, you're interacting with actions on controllers that are normally supposed to give you data, not a user interface. You can't just give them a link and expect them to do something with it.

Thus, if you're dealing with authentication over Web API, what is an effective and secure way to allow users to reset their passwords and also communicate the new password to them?

Was it helpful?

Solution

The thing to remember in this scenario is that Web API is just that: an API. Even though there might not be a website, there is still a user interface somewhere (an actual website, or a WPF application, or a mobile application - doesn't matter). So the usual secure "forgotten password" functionality can still be implemented.

There is one difference, however. Instead of sending a link, send the token itself. The UI then provides the place to enter the token. The steps to follow are below:

  1. The user wanting to reset his password goes to the appropriate "Forgotten Password" screen in the UI.
  2. The user is prompted for his username.
  3. A token is sent to his associated email address in plaintext. The hashed version is stored in the database together with an expiry of, e.g., one hour from now.
  4. The user enters the token in the next screen.
  5. If the token is valid, the user is taken to a screen in which he can enter a new password (without having to enter the old one - the token already authenticated him).

Sending a plaintext token via email might sound a bit like sending a password via email. However the fact that it expires after a short period of time gives an attacker a very small window of opportunity to use it. Also, the token is one-time, and is discarded upon use.

OTHER TIPS

There are two concepts you're addressing in this question: password reset and the mechanics involved, and the proper way to authenticate a user to a web API. I think it's important to draw a distinction between them and to understand the latter first.

Imagine you have a web application and a protected resource (web API). The web API requires that all callers must be authenticated by some mechanism. One way to allow a user to authenticate to the web API is to present credentials directly to the web API, but this presents many other issues such as the web API needing to store/maintain/access user account info, the security weakness in sending passwords along the wire in this fashion, the broad scope the web API has to act on the user's behalf when it obtains their raw credentials, etc.

You've probably heard of OAuth 2.0, which addresses these problems. A better way of accessing a protected resource (web API) is to add an authorization layer. For example, a web app presents a dialog for entering a user's credentials, which are then sent to an authorization server and validated, which produces an access token. The access token can then be used to authenticate calls to the web API on behalf of the user (or on behalf of an application using client credentials grant). Using this flow, the web API doesn't need to authenticate users directly, it can be much more lightweight, and many other security issues with the other flow are addressed. See the OAuth 2.0 specification for more detail.

Getting back to your example, a better answer is that you manage password reset at a different level. Your web API shouldn't have to know about the user and password at all, let a lone resetting it -- it should just receive a token and validate it. This allows you to play around with your desired password reset method and it won't affect access to any of your downstream resources.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top