Introduction to Password Security

Earlier this year I gave a talk on Password Security at Digital Croydon #5, and
didn't want to simply put up the slides without any commentary, so I've written
this article to accompany them. It is primarily for the benefit of those that
attended - by which I mean it wont explain every slide or go into detail on
everything the talk covered, but will explain the key points, provide links, etc.

Similarly, as mentioned in the talk, it didn't cover everything there is to
know, and this article wont do that either - it's an introduction, not a
comprehensive guide.

(At some point I do hope to write up more detailed articles, both on the points
covered and on related subjects - if/when that happens I will add the relevant
links to this article.)

Wording

I use the term "passcode" in preference to "password", because thinking in terms
of a word is the wrong approach. A single word is not a strong passcode, multiple
should be used. I used to use "passphrase" but that's also wrong - whilst a
phrase may be better than a single word, a line of nonsense is better - several
words that do not belong to a known phrase. (More below.)

Avoid If You Can

If possible, avoid the need for user accounts (and thus passcodes). This isn't
an option if correctly identifying users is important, but not all situations
require user accounts.

For example, a customer support portal may not need user accounts for basic
support or one-off requests.

Similarly, if all you're doing is storing preferences, default to using cookies.
Allow users to create accounts if desired, but if linking preferences to a
machine is ok then allowing just cookies will reduce the number of accounts
needed, and thus present a smaller target.

Store Passcodes Correctly

Not storing as plaintext is obvious - nobody who isn't a complete novice would
insert passwords direct into their database.

But there are other ways to store as plaintext - if you log errors and include
the form post data in that log, unless you've excluded passcodes you'll be
storing them plaintext. Strip them out before storing the data - and don't forget
to do the same with credit card numbers and any other sensitive information!

Another overlooked method of putting passwords in plaintext is submitting forms
over HTTP - whilst HTTPS is becoming increasingly common, it wasn't that long
ago that many sites had login and registration forms submitting over HTTP, and
thus were sending those details in plaintext for any intermediary to read. Going
HTTPS is cheaper and easier than before.

A common perceived step-up from plaintext that isn't actually much of an
improvement is thinking hashing will solve the problem - it doesn't.

MD5 is broken - do not use MD5 for anything but especially not passcodes.

SHA is designed to be fast - it wasn't designed for passcodes, don't use SHA.

Anything you try to write yourself - or any code you grab from some other
developer online is unlikely to be secure. Don't try writing your own algorithms

There are advantages/disadvantages to each, but with suitable parameters they
are all acceptable. Obviously where security is critical you should read up on
each and make your own decision, but otherwise just use bcrypt.

Implementations of bcrypt are available for all major languages - for convenience
the results of appropriate searching are included below, but, as with all security
matters, verifying with relevant language/library curators is obviously prudent.

Again, the above list is not endorsement or recommendation, merely the result of
searches looking for the canonical or most popular library.

cfPassphrase is my own project, but it only wraps jBCrypt for easy use in CFML
- i.e. it re-uses existing cryptographic
algorithms, and so does not violate the "don't write your own" directive.

Stronger Passcodes

Correct storage is only part of the solution - it's important to educate users
correctly on what makes a strong passcode - and the preconceptions that many
developers have about this are either inaccurate or incorrect.

The most important factor in passcode strength is length. Longer is stronger.

But this is not just about character length - "aardvark" is three times longer
than "ant", but they are both only one word long, thus neither is strong.

Likewise, "to be or not to be" is six words, but it's one phrase - one very
well known phrase, made up of short common words - and thus is not a strong
passcode. It is less weak than "ant", but that's not enough.

No single unit - nothing that appears on any list - is strong on its own, and
the more frequently it appears, the weaker it is.

Whilst length is most important - twenty common units (whether characters, words,
phrases) is likely to be more secure than a single uncommon unit - using uncommon,
unpredictable units is still important.

The old recommendation for making uncommon units was letter substitution -
swapping letters for numbers and symbols - but with the increasing speed of
computers, and thus the number of attempts that can be made, this is no longer
sufficient. There are only so many alternatives for each letter (and predictable
substitutions are already on the lists password crackers use).

Minimum character length should be at least 8. Even with good storage, cracking
passcodes of six chars or less is too fast.

If you're wondering about how you go about implementing the above, you don't.
The hard work is done for you with the JavaScript library
zxcvbn.js

As the user types their passcode, you feed it into the function this library
provides and - based on the length and uncommonness of units - it works out how
long it would take an attacker to crack, and converts this to a number which can
be used to populate a strength value.

It also provides a breakdown of where that number comes from - i.e. it identifies
common words, keyboard patterns, etc and determines how much they contribute in
making the passcode stronger. This information can be used to give hints to the
user, e.g. "don't use common names", or "a sports team and number is not secure".

Of course, make sure they are only hints and you're not giving away what the
user tried to anyone looking over their shoulder.

Common Mistakes To Avoid

A very common practice is expiring passcodes on a regular cycle, each month or
six weeks, or similar. The idea behind this is that if a passcode is compromised
it's only good for a period of time.

Not only is that premise itself invalid (once an attacker has access, they usually
don't need that long and can use privilege escalation vulnerabilities to avoid
it), but research conducted by Microsoft
discusses how this results in weaker user passcodes, and causes people to simply
add a sequential aspect which is all they change each month and makes it trivial
to predict what their next change will be.

If an attacker gains access to the database containing passcode hashes, all
passcodes need to be expired as soon as possible, so they can be changed before
an attacker has a chance to crack them. (And if users do not change them within
a suitable timeframe, the accounts should be locked.)

How Users Can Protect Themselves

Users need to assume that developers are incompetent and not storing their
passcodes correctly. Assume that every site you visit is storing your details
in an insecure manner which can be attacked at a rate of 200 billion every second.

Never use anything less than eight characters as an absolute minimum - twelve or
more characters is better, so long as its not a single word.

One method to create a long but memorable password is to pick five or six
uncommon words at random, put them into a made up nonsense phrase that will not
appear on anyone's list. Use uncommon misspelling plus mixed punctuation to make
it even less predictable.

You can use the six letters that start each word as a written reminder - they
should be enough to jog the memory without giving away the words to anyone who
finds the written copy (write on paper, not on any Internet-connected device).

Block third-party JS and adverts

If a web page includes third-party JavaScript - and remember that many adverts
use JavaScript - nothing on that page should be considered secure.

It is trivial, without triggering a browser's cross-site scripting protection,
to redirect a form to a different location, and thus have users providing their
login details to someone else. (I have code that proves this, and I'll be
writing it up for a future article as soon as I have time.)

Whilst you might trust the site in question, you also need to trust everyone
whom that site trusts, and then everyone that they trust, and so on - it doesn't
take long in a chain of trust to find someone making a mistake and trusting the
wrong person. Why take the risk?

You can use plugins such as Adblock Plus,
Ghostery and/or Privacy Badger
to block scripts from most likely to be malicious sources, or you can use
NoScript to block all scripts and gradually whitelist
only the ones you need.

Complain about bad practices

Education goes both ways - whilst most users pick weak passcodes, it's equally
true that most developers don't know how to store passcodes securely - so if you
find a service that isn't doing it right, you need to complain - both to protect
yourself and fellow users.

These are numerous signs that passcode security is not taken seriously - if
length is limited, any punctuation or symbols are disallowed, you ever see your
passcode in plaintext, if they can be reset with public information (like your
mother's maiden name), etc.

Some companies/developers claim they are doing things securely when they're not
(or have some parts secure whilst others are wide open), but they're probably
not doing it deliberately - don't just tell them they're wrong, give them the
information to help them understand why and how they can fix it. If they still
ignore you, let them know you'll go public if it's not fixed - bad PR may be a
bigger motivation than protecting users.

I hope this has been helpful, and one last tip: if you're unsure about anything
involving passcodes or security, don't assume the first person you ask is
correct, or even the tenth person - there's plenty of well-intentioned but
incorrect information out there - so look for qualified experts: cryptographers
or security specialists with clear credentials.