ericelliott/credential

Passwords are obsolete

ericelliott opened this issue · 23 comments

The biggest threat to password security right now is passwords that have already been stolen from systems that aren't secure.

The runner up is brute force, and brute force can be distributed and optimized with frequency-sorted password dictionaries.

We should encourage all credential users to also employ:

  • 2-factor auth
  • dictionary-based password blacklist

How can we better encourage them in the docs?

Is it possible to encourage them programatically, as well?

Ideas

Add a password validation function which:

  1. Makes sure the password is sufficiently secure (based on config)
  2. Asynchronously tests against a password blacklist

This idea complicates security, because we'd need a database of blacklisted passwords, and we'd need to keep a candidate password in memory long enough to check against the blacklist. If an attacker got access to our blacklist, they could just filter their frequency sorted dictionary. If the attacker gained access to program memory, they could sniff the pending passwords.

I still think a small enough blacklist would be a good idea.

The software architect side of me is convinced this belongs in a different module. The lazy developer side of me is convinced that if it's in a separate module, few developers will bother with it.

However, maybe we could put it in a separate module, and refer to it in all the docs. Show it in the installation steps, show it in the example sequences, etc... Make it really obvious that these modules are intended to be used together.

We could do the same thing with a 2FA solution, though I'm inclined to use an off-the-shelf 2FA instead of rolling our own.

Is there a good off the shelf password validation library we could use?

Also, you should limit the number of failed authentications to the same user per time to make brute forcing impossible.
These things are very application specific though.

Also, you should limit the number of failed authentications to the same user per time to make brute forcing impossible.

Absolutely. Should we add hooks or documentation to support that?

you should limit the number of failed authentications to the same user per time to make brute forcing impossible.

This helps protect against online attacks, but does nothing to counter an offline attack.

I have been mulling the problem of authentication for a long time. I have recently worked on a project with an alternative authentication model, which I call second channel, and it ought to be peer reviewed so this might be a good spot to start. It works like this:

  1. A user provides an email address.
  2. A unique PIN (a short set of random characters) is sent to the user via that email.
  3. The PIN can then be used to authenticate.
  4. There can be only one active PIN at at time.

The system throws up a flag or fails outright if:

  1. The PIN expires, after e.g. 15 minutes;
  2. Too many attempts can be made to log in with a PIN; or
  3. Too many PINs are requested.

The key here is that the email is the primary mechanism for identification, and a second channel (not the web-page's Internet connection, e.g. email) is a primary mechanism for authentication. It could be another channel, such as text message, phone message, or any arbitrary message system. One could still add second-step e.g. Time OTP or Event/Counter OTP per rfc6238, or a permanent password as an alternative. The point though is that we primarily authenticate on something the user has - a phone, email address, messenger account - that they consider to be secure.

The inherent problem with authenticating humans is the brain. The pain this solves is that of remembering a password, as memorability is proportionate to simplicity and frequency of use. Infrequently used sites are particularly vulnerable because users regularly forget their credentials - or use simple, easily guessable ones.

The second channel system generates unguessable authentication codes, eliminating both weak passwords and memorability from the equation. It also reduces the time window of exposure to password dumps or log-leaks, since the PINs expire.

The weakness is that the strength of the authentication is the security of the users' email. That said, the email vector is almost always there anyway since automated password recovery is almost always via email. The second channel has that exposure, but without weak passwords exposure.

In an ideal world user would all have OpenID or OAuth2 or SAML (which effectively serves as a second channel).

Thoughts?

The key here is that the email is the primary mechanism for identification, and a second channel (not the web-page's Internet connection, e.g. email) is a primary mechanism for authentication.

Isn't this paper-thin protection from coworkers on a corporate lan where they could easily sniff network traffic and steal each other's pins?

Or even total strangers on a poorly secured wifi network?

The point though is that we primarily authenticate on something the user has - a phone, email address, messenger account - that they consider to be secure.

Yeah, but you can't just use a single channel. You need a secret and something the user has.

That should be something relatively hard to steal, though, like a dongle, or a cell phone. It's way too easy to steal emails.

I don't think email-only is much more secure than a password.

Some major concerns:

  • as you mention, email is effectively same as OAuth2 and friends - just another single-sign-on
  • single-sign-on is not really distributed, and doesn't work offline.

Isn't this paper-thin protection from coworkers on a corporate lan where they could easily sniff network traffic and steal each other's pins?

Or even total strangers on a poorly secured wifi network?

That's why it has to work local and offline, to never expose your keys. Some of the attack vectors you mention though is solved by proper HTTPS.

I see no other real solution than a browser utilizing asymmetric keys, either native or with a plug in, and then preferably a JavaScript API for webmasters to query.

And this is, I believe, what @substack did with his hyperboot.

Thanks all for the great feedback. Bearing in mind that I am probably wrong about everything I am about to say, I have some thoughts:

On sniffing - to be secure in any case folks will need to check their email over IMAPS or POPS (i.e. encrypted, as @tjconcept notes), and this will be a policy for any competent company. To identify the client browser one could also issue a server-client PK challenge i.e. the server challenge the client on a public key the client sent with the request for a PIN (entropy/etc problems aside, until WebCrypto lands). One could check that the remote address of the user consuming the PIN is the same as the IP that generated it, but that is of no help with NAT, though perhaps for IPv6.

A more precise analysis of the email exposure is: With access to a co-workers' email there is nothing stopping a malicious person from sniffing the email password, temporarily changing the password (so updates are not propagated to the victim), and using the typical automated process for resetting the password over email, then deleting the email trail and changing the password back (or just being quick about it). That exposure exists with typical password-credentials procedures in existence today. The second channel reduces exposure on other vectors (password dumps, log dumps, weak passwords), while maintaining the same exposure to email sniffing.

@ericelliott Is your only concern email sniffing? Would you agree that if the email/2nd channel is secure that the concern is moot (in the sense that this method is at least as secure as passwords)?

It is worth bearing in mind that the level of security all depends on the vectors perceived to be of concern. If you are handling information related to people accused of terrorism (which I have), then for example you'd be mindful of mobile phones since it is common knowledge in security circles that the phone grid is riddled with holes and likely even less secure than encrypted email (e.g. PGP / Silent Circle). Equipment for $30 in over-the-counter tools can be used to sniff text messages out of the air; imagine the capabilities of those with insider information and industrial resources. If one really wants to get a secure but still usable computer, you'll need a handle on the Rainbow Series and TEMPEST shielding against EMF/Van Eck Phreaking. That's just not practical, desirable, or necessary for a Javascript library for authenticating web requests. That said, @ericelliott What's your vision of this project? :)

@tjconcept - I don't understand what you mean by the "local and offline" requirement. I'm just confused. :) Do you mean for an autonomous second factor, like an OTP (i.e. one that does not require transmission from server to client)?

Just incidental, for discussion, speaking of local and offline, another hardware option I like is Yubikey.

Another thing to note, if you get a phone with an OTP like Google Authenticator for a few minutes you will be able to work back to the root key — by my napkin-based math, with eleven or so one-time passwords one can get the root key used to generate SHA-1 OTP codes that are used by Google Authenticator.

The practical concern is critical, since perhaps the most important point is that normal humans need to use it efficiently. If security is too difficult a process, people will gravitate to an alternative service - so firms will be unwilling to adopt it. If you make a bunch of money you can get insurance to cover cyber-risks. Humans are not efficient at using strong, memorable passwords.

One objective of this project could be to delegate to potential users the choice of the level of security so users may balance the practical functional constraints against the cost-risk-insurance. Even sneaker-net is vulnerable to social engineering, a Court order, an estate trustee, and truth-serum; you cannot protect against everything. In my mind, the objective of a security process ought to be the practical implementation of identification and authentication in such a manner as to reduce the aggregate exposure to plausible risks appropriate for the average cost of exposure. Those variables all change depending on the project and insurability.

Sorry for the length, but I hope that offers some food for thought. :)

Oh - I would add that I am not sure about the value of password strength tests. Most people end up forgetting strong passwords and resetting their passwords every time, or re-use the same password everywhere (making it susceptible to cross-site mining).

I'll say it again, this time a little more bluntly: Email can't be trusted as a single source of authentication. Neither can passwords.

Is email alone safer than passwords alone?

That's like asking which tissue paper is harder to punch a hole through.

You must have a multi-factor challenge to be reasonably safe. I think we should guide users to the most reasonably safe mechanisms.

A password + email challenge is better than no challenge. Password + OTP is better (we're assuming only the user has the device and OTP codes being generated, here).

The same IP check at least ensures that if there is an attacker, they must be close.

For UX, I don't mind using only the username / password combination after you have already authenticated with other factors. Remind the user to reauth with multi-factor overy few days instead of daily, for instance. Always re-auth if they change machines / browsers.

I'm not sure how much, if any of this belongs in this library, but we should at least document some baseline recommendations.

I also do think we should be in the business of validating passwords to ensure that they at least meet a minimum baseline of password strength. This can be as simple as a password length check.

I don't understand what you mean by the "local and offline" requirement.

I mean that in order to keep my secret a secret, I need to be able to create a dervied key on my local machine.

I think, for now, that we should focus on making this library as good as possible within the current scope/API - that's still a reasonable improvement to the current situation in node land - can we agree on this?

.. and then continue the discussion on a specific implementation for a general 2FA (or several-factors) scheme that eventually can be built in another module, and used here, or vice-versa. We might even refactor this module to just use other modules containing different "factors" whereas one is a stored password hash.

Sorry to belabour the point, but I am still wondering what the substantive concerns are with a second channel.

I'll say it again, this time a little more bluntly: Email can't be trusted as a single source of authentication. Neither can passwords.

Why do you believe email cannot be trusted as a single source? Ruling out sniffing, what other concerns do you have? Sorry if I missed it, but that was the only concern I saw mentioned.

There are risks to passwords that do not exist with a second channel as a primary authenticator, including: mass account disclosure, weak password brute force/rainbow tables, and cross-site mining. Do you disagree, @ericelliott ? I mean if you can make the default mechanism of identification and authentication more secure by removing exploit vectors and improve the user experience, why wouldn't you?

The idea is to turn the second channel into a proxy for identification and authentication - so the service will never be more secure than the other channel. Of course 2fa is better, if you can get users to do it. If you cannot have 2fa (because folks don't get it or use it or they abandon you for mandating it), it seems apparent that email-only over an encrypted channel is substantially more secure than passwords. I am open to being convinced otherwise, but the reason just has not been clear to me.

A second channel need not be email, it is just one option. Telegram is defensibly secure and achieves the same. You just have to force the Telegram app on people. Or create a custom app; the point is that the user has a pre-established communication mechanism where they are the verified endpoint, and users can encrypt the contents of their phone and lock it with a PIN.

I mean that in order to keep my secret a secret, I need to be able to create a dervied key on my local machine.

@tjconcept - with a second channel authentication the only secret is ephemeral and generated on demand, so I am not clear how the local and offline requirement applies. So sorry if I am being dense on this point. :) I am also not clear on what you mean by single sign-on not being distributed - what's being "distributed" mean?

Sorry for the length, again.

All to say, I agree with the title of this post that passwords are obsolete. :) There appears to be a alternative to passwords by using a second channel for authentication, with substantial benefits, where 2fa may not be viable. It'll never be as good as 2fa though.

with a second channel authentication the only secret is ephemeral and generated on demand, so I am not clear how the local and offline requirement applies. So sorry if I am being dense on this point. :) I am also not clear on what you mean by single sign-on not being distributed - what's being "distributed" mean?

If a token from an e-mail is used as the key, then that's a derived key, and my secret is not exposed - in this step at least. The problem is that I need to log in to my mailbox somehow, and then I'm once again handling my secret over to some remote server. I'm talking about the fundamental flaw that regular users are not using asymmetric keys.

I do believe a pin by e-mail is more secure than an on-site password solution, simply because e-mail providers have more resources to protect users passwords - for instance as @ericelliott mentioned in relation to the number of iterations (see PR comments).

It's still a sucky UX though - in particular from a cell where multitasking is limited.

You could enhance it a tiny bit by giving people a link to click with the token in the URL, in stead of having them to manually type it in.

@tjconcept Oh, perhaps I see what you mean. Let me see if this clarification makes sense:

The process I have uses the PIN only once, for validating the identity of the user. Once validated, a token & hash are created with e.g. itsdangerous — the secret for the hash being stored only on the server. The PIN is discarded/"consumed". The token can then safely include the identity, authentication permissions, and recurring restrictions such as IP address e.g. {userId: "name@domain.com", accountId: "accountId", onlyIPs: ["192.168.44.1"]}.

Is that what you were referring to? Does that clarify at all? Or am I way off the mark here?

The security of the service will always be susceptible to flaws in the identification channel. A service like Telegram could increase that somewhat.

The UX is not great, particularly on a phone - as you say, being ever so slightly better than re-requesting the password every time. :) A click-link would be an improvement, I agree.

@brianmhunt I understand your application perfectly fine, and no, it does not expose the users secret, but I don't think it's a solution to the fundamental problem of authentication as you'll still need other means of authentication for your inbox.

@tjconcept Thanks - it's just the "doubling down" on email (or whichever second channel)? I wonder if that's where something like Telegram could come in as an authentication mechanism.

Thanks guys! I really appreciate the work that both of you have put into this.

First, I agree that a lot of this is out of scope for this module, but I do strongly believe we should at least make it clear in the documentation that passwords alone are obsolete and should not be trusted.

I agree wholeheartedly that we should try to solve the problem in other modules. Maybe Credential docs are a good place to link to those other modules, but I'm not sure to what degree it should integrate with those other modules. I do think it may be a good idea to require a 2FA token in order to get an affirmative response from the verify() function (or maybe an authenticate() function that wraps it, but in that case, verify() should become private, rather than public API).

Any thoughts on that?

As for email. Brace yourselves. This is about to get ugly (in friendly spirit -- we're collaborating, I'm not trying to tear anybody down, just want to shatter some overconfidence...). ;)

Email is a really terrible security mechanism

There are risks to passwords that do not exist with a second channel as a primary authenticator

And vise verse. The primary risk with email is that you're offloading security to untrusted systems. You have no idea if the email provider is following best practices (unless you disallow everything but GMail, and even then, it interfaces with 3rd party email servers, so there's an extended untrustworthy trust zone).

  1. You can't guarantee that email will always be encrypted in transit and storage.
  2. You can't guarantee that the intended recipient is the only person with access to the email account.
  3. The email account itself may be only protected with password security, so some of the same exposure from password risks leaks into the problem. See also point 2.

Email is one of the least secure protocols on the internet and it boggles my mind that we rely on it so heavily for security. The only way to guarantee safe email is to lock it down so that it only gets passed over secure servers and never gets forwarded, and that's completely out of your control.

I'll say it again: Never trust email as the only source of authentication security.

while (wat) {
  console.log('2FA');
}

I do believe a pin by e-mail is more secure than an on-site password solution

No, it isn't. It's just distributing the risk into the unknown reaches of cyberspace where you can't see the security flaws.

Both factors are wet paper towel security on their own, but when you combine them to form 2FA, suddenly they become a steel wall security fortress, because it there is a much, much smaller chance that an attacker has both the resources to crack the password and access to the 2FA token.

I say that email is an especially weak factor for 2FA because if an attacker has access to either the server OR receiver network and the email is dispatched in cleartext at that point (you don't want that, but you don't control that from application space, that's a system configuration concern, and some of the configuration you have to trust isn't even controlled by your org), you're pwned.

The key to good security is to limit trust zones as much as possible so that there is a limited surface to scan for attack vectors. Email does the opposite of that. It spreads the trust zone out so far you literally can't measure or predict how much of the world you have to trust. Basically, your trust zone (and potential attackable surface) grows to virtual infinity.

The advantage of OTP is that you don't have to send a secret message out into the untrusted shark infested ocean.

Related:

Thanks so much for the substantive reply @ericelliott .

I agree with the 2fa being in other modules, and providing an option for them to integrate. One might consider an umbrella project that does the management of modules, like PAM.

On the email, I really appreciate your effort to spell out the concerns. Aside from a couple policy points, I'll just rebut here for convenience of readers, but it's largely repeating what's above.

  1. You can't guarantee that email will always be encrypted in transit and storage

Agreed. The security of the system cannot be greater than the security of the second channel.

  1. You can't guarantee that the intended recipient is the only person with access to the email account.

Agreed. Again, the security of the system cannot be greater than the security of the second channel.

  1. The email account itself may be only protected with password security, so some of the same exposure from password risks leaks into the problem. See also point 2.

Agreed.

Now the points begin to differ.

Foremost, email is not the only available second channel. There is Telegram, etc. Any medium with a verified endpoint. Security of email can be dramatically improved with e.g. PGP, and every major third party email provider now uses a 2fa and requires https. But taking email as the only point of concern for the purposes of the discussion:

Email is one of the least secure protocols on the internet and it boggles my mind that we rely on it so heavily for security.

Agreed. At the time we designed email we did not have security in mind - it was a more innocent (naïve, frankly) era. That said, by being a known and common target email is also one of the areas that receives the most dedicated funds and attention in terms of monitoring and improving security.

That said, even Yahoo email was hacked. So was LinkedIn.

One major problem of a second channel is exactly as you note, when it happens to the email provider. Those with 2fa on Yahoo were unaffected. That said hacking Yahoo did not automatically lead to third party disclosure - attackers would have to know the account existed on a third party and then reset the password (or use OAuth2/etc).

A key difference between Yahoo & LinkedIn is: had LinkedIn used a second channel for authentication instead of password the hack would have been largely irrelevant. The LinkedIn database would have stored only a few ephemeral and rapidly expiring keys (by the time the accused got out a demand letter the exposure would've expired).

Which is a critical improvement: by using a second channel, one eliminates the possibility of mass disclosure of credentials. The major hacking events hitting the news have been consistently the leaking of bundles of poorly protected passwords. Once disclosed it is just a matter of time, equipment, and energy.

Both factors are wet paper towel security on their own, but when you combine them to form 2FA, suddenly they become a steel wall security fortress, because it there is a much, much smaller chance that an attacker has both the resources to crack the password and access to the 2FA token.

Nobody has said a second channel is better than or compares with 2fa. For a lot of folks though, 2fa is not realistic.

So another critical improvement is that a single source of authentication is better than many. It reduces the attack surface, as you note. Password auth requires taking responsibility for storing, hashing, transmitting, logging, resetting, etc., plus the user exposure of weak passwords and cross-site mining. By delegating to a second channel the attack surface reduces to the authentication of that channel and the security of the transmission. The same risks are there as password auth, but they have been delegated.

An aside, there are entire companies dedicated to the password centralization benefit alone e.g. 1Password and LastPass.

I say that email is an especially weak factor for 2FA because if an attacker has access to either the server OR receiver network and the email is dispatched in cleartext at that point (you don't want that, but you don't control that from application space, that's a system configuration concern, and some of the configuration you have to trust isn't even controlled by your org), you're pwned.

How do the noted attacks not also undermine an automated password-reset process? If someone has the email server or the endpoint, how are you not already owned? SMTP being unencrypted is a relevant concern. An assailant still has to compromise a jump on the route.

Hacking an email server, endpoint or jump on the SMTP route are all expensive and risky. One would generally do this only for a known target with perceived or apparent value. By using a second channel you have eliminated the entire class of "slurp and fry" followed by a demand letter that starts with "we have your passwords".

LinkedIn may not have been a target if all the attackers could get were email addresses. Hackers would then need to hack the respective email - likely through a variety of providers. LinkedIn would not have been low hanging fruit, and so less of a target, and in any case was not responsible for the security of the email so it would not have taken the hit to its reputation for security.

The advantage of OTP is that you don't have to send a secret message out into the untrusted shark infested ocean.

I favour OTP. That said, it's not perfect. It can be lost; it can be worked back to a root key with a few data points; a persistent secret is stored on the server and client.

Also - on the links - Email spoofing is spoofing the sender (i.e. SMTP); I do not see the relevance. IP spoofing is still MITM or mitigated with https. Not sure Zones of trust is a bit confusing; I find the OWASP threat modelling a clearer reference.

Okay - that's all I have to say, I promise! 😉 But seriously @ericelliott - you have been oddly resistant to acknowledging the benefits of a second channel over passwords. Is there any particular reason for this, or are you just focused on 2fa?

Sorry for hijacking the issue (on topic though it may be); it has been a very helpful discussion for me to get a clear mind on what's relevant.

Let me be clear. I'm not at all resisting the use of email as a second factor. I'm resisting it as an only factor, because it's no more secure than passwords.

I agree that there is substantial risk in storing passwords at all, but as long as alternatives are not clearly dominating the industry, people will need a password hashing library that doesn't suck.

I believe Credential should be available for that purpose but I believe the documentation should clearly warn that password security is not safe and that people should be very careful with it.

You seem to be asserting that we should not be storing passwords at all.

I agree, but the complete solution is not one solution. The complete solution is at least two solutions: for example, delegated auth + second channel (login with Facebook or Twitter Oauth, Then get a token via second channel, for instance).

The problem with delegation is you release control of one of the auth mechanisms, so you no longer know the auth factor. Ideally, each channel uses a different auth factor. See multi-factor auth section from my book.

In any case, aside from recommendation in the docs, this all seems out of scope for Credential.

We should still decide what to reccomend. I'm not going to ask my users to install yet another security app unless it has good traction. Google authenticator and Authy are pretty good in that respect. I think Authy even has Bluetooth support so it can automatically log users in without waiting for them to manually enter the OTP.

That plus delegated auth seems like a nice solution to me.

We should favor auth that has minimal impact or familiar flows for users. :)

Check out Authy's bluetooth integration. I really think that's the best security we have available right now. If we can implement one-click login with FB / Google federated auth, then also require an Authy token, we can completely eliminate the need for password auth.

With bluetooth auth, it would be even more convenient than username / password auth.

Thoughts?

Closing all stale issues and PRs. Please update, ensure all tests pass, and reopen if you really want this in.