PLAINFINCH learn by building

Strong passwords

You will set a bird club's join form to refuse weak and leaked passwords, then watch two attacks fail.

What makes a password strong?

A password is strong when it is hard to guess for someone who knows how people choose passwords. That last part is what most rules miss. Attackers do not try every possible combination in order. They start with passwords that real people have used, taken from years of leaks, then try those with common changes: a capital first letter, a 1 or ! at the end, an a swapped for @. Birdwatcher1 looks varied and is near the top of the list.

Two things make a password hard to guess: length, and not being something people commonly pick. A password generated at random by a password manager, such as 20 characters of mixed letters and numbers, has both. So does a passphrase of four or five unrelated words, like kettle orbit marsh pencil, as long as the words were picked at random and are not a line from a song.

Why does length beat symbols?

Each extra random character multiplies the number of possible passwords. One more random lowercase letter multiplies the attacker's work by 26; one more character picked at random from every key on the keyboard multiplies it by about 95. People do not add symbols at random, though: they put ! at the end, and guessing tools try that first. A symbol in a predictable place adds almost nothing, while extra random length keeps multiplying.

Rough figures help here. Treat them as orders of magnitude, since they depend on the hash and the hardware. Against a slow hash such as bcrypt, an attacker with a stolen table might manage thousands of guesses a second per account. An 8-character password built to the usual rules, such as Heron20!, follows a pattern that guessing tools try early, so it falls quickly. A random 16-character password or a five-word random passphrase would take longer than anyone will spend. Length is easy to explain, easy for people to meet, and works.

Current guidance from NIST in the United States (Special Publication 800-63B) sets it out: a minimum length of 15 where a password is the only sign-in factor, and at least 8 when a second step is also required; allow passwords of at least 64 characters; allow spaces and any characters; and do not demand a mix of character types. The NCSC in the UK gives similar advice and suggests three random words.

Easy to guess:   Birdwatcher1!
Hard to guess:   kettle orbit marsh pencil
Hard to guess:   r7Vq2mWzK9pLx4Tn (from a password manager)
FigureAn attacker's guessing order from first to last. Password1!, Birdwatcher1! and Heron20! all sit near the start because tools try leaked passwords and common patterns first. A four-word random passphrase and a 16-character random password sit far beyond where any attacker gives up.An attacker's guessing order from first to last. Password1!, Birdwatcher1! and Heron20! all sit near the start because tools try leaked passwords and common patterns first. A four-word random passphrase and a 16-character random password sit far beyond where any attacker gives up.
Guessing tools start with real leaked passwords and the usual tweaks, so a capital letter and a ! barely move a password along the line. Length chosen at random moves it out of reach.

Why refuse common and leaked passwords?

Your site cannot see what members type elsewhere, but it can refuse the choices that attackers try first. Two lists do the work. A list of the most common passwords, from a few thousand to a hundred thousand entries, stops password1, qwertyuiop and birdwatcher1. A check against known breaches stops passwords that have already appeared in someone's leak, which are exactly the ones credential stuffing uses.

In the lab, block_common_passwords = yes and check_breached_passwords = yes stand in for those checks at sign-up. With both on, the guessing bot's list contains nothing a member could have chosen, and leaked pairs no longer match any account. That is why both attacks failed in the task without any change to server.js.

On a real site you would run these checks in the join route and the change-password route, before hashing. The common list can be a text file on your server. For breaches, a widely used approach is the Pwned Passwords service, which uses k-anonymity: your server hashes the password with SHA-1, sends only the first five characters of that hash, and gets back a list of matching suffixes to compare locally. The password itself never leaves your server. That SHA-1 is used only to look up the leak list; it is never how you store passwords.

What should your join form ask for?

Keep the rules short and explain them on the form. A minimum length of 12 is a sensible default for a small site where members also have a second sign-in step; 15 if the password is the only thing protecting the account. Allow at least 64 characters so passphrases and password managers fit. Allow every character, including spaces and letters from any language.

When a password is refused, say why in plain words: "This password appears in known data leaks. Please choose a different one." Members who understand the reason pick a better password. Members who get a vague error add 1 to the end.

Let password managers do their job. Use autocomplete="new-password" on the join form and autocomplete="current-password" on the sign-in form, and do not block pasting. A manager can then suggest a random password and fill it in later, which is the easiest strong password a member will ever use.

<label for="pw">Password (at least 12 characters)</label>
<input id="pw" name="password" type="password"
       autocomplete="new-password" minlength="12" maxlength="128">

Should members change passwords regularly?

No, unless there is a reason. Forcing a change every 90 days was common advice for years, and it backfired. People faced with regular forced changes choose a pattern, such as Heron-Spring becoming Heron-Summer, which an attacker who has the old one guesses at once. Current NIST and NCSC guidance says not to require changes on a schedule.

Ask for a change when you have evidence of a problem: the password turns up in a new breach, the member reports something odd, or your own site was breached. In that case, require a new password at next sign-in, explain what happened, and make sure the new one passes the same checks as at sign-up.

What do strong passwords not protect against?

A strong password does nothing if the member types it into a fake sign-in page, if malware on their laptop records it, or if your site stores it badly. It also does nothing against attacks that never use a password, such as stealing a sign-in cookie through a script in a comment.

That is why password rules are one wall among several. The next lesson covers storing passwords with a slow hash, so a stolen table is hard to use. The one after that covers sign-in sessions. Two-step sign-in, and passkeys in particular, protect members even when their password has leaked. The rate limit from the earlier lesson slows down guessing against members who chose badly before your rules existed.

Where does the lab simplify?

In the lab, the two settings in site.conf instantly change what every member's password could be. On a real site, the checks only affect passwords chosen after you add them. Members who joined last year still have whatever they picked. Check existing passwords at their next sign-in, when the plain password is briefly in memory, and ask anyone on a leak list to choose a new one.

The lab also blocks credential stuffing completely once leaked passwords are refused. In reality, breaches keep happening, and a password that was clean when a member chose it can appear in a leak next month. A second sign-in step covers that gap. The guessing bot in the lab uses one fixed list; real tools use far larger lists and rules for changing them, which is one more reason to require length.

What do AI tools get wrong about password rules?

Ask an assistant for a password validator and you will often get the old rules: at least 8 characters, one uppercase, one lowercase, one number and one symbol, sometimes with a maximum of 16 or 20. That combination accepts Password1! and refuses a 30-character passphrase. Some also suggest forcing changes every few months or blocking paste on password fields.

Check generated sign-up code for a minimum length of 12 or more, a high maximum, no character-type rules, a check against common and breached passwords, and the right autocomplete values on the form. If the assistant suggests a strength meter, check what it measures: a meter that rewards symbols over length teaches members the wrong lesson.

Field notes

  • Length makes a password hard to guess far more than swapping in symbols does.
  • Refuse common passwords and ones that appear in known leaks.
  • Ask for at least 8 characters, allow long ones, and let password managers fill the box.
  • Forced regular password changes push people toward weaker, predictable passwords.

Easy to get wrong

Character rules produce predictable patterns such as Birdwatcher1!. Length and list checks stop the passwords attackers actually try.

Short limits block passphrases and long random passwords from managers, which are the strongest choices members can make.

Scheduled changes push people into patterns that are easy to guess from the previous password.

Blocking paste stops password managers, so members fall back to short passwords they can type from memory.

Questions people ask

Is a passphrase really safer than a complex password?

A passphrase of four or five randomly chosen words is long and easy to type. A short complex password usually follows a pattern guessing tools already know. Random choice is what makes either one strong.

Should I show a password strength meter?

Only if it measures guessability, for example with the zxcvbn library, and does not reward adding symbols. A clear message when a password is refused does more good.

Can I check leaked passwords without sending them anywhere?

Yes. Range-based lookups send only the first five characters of a hash of the password and compare the results on your own server.

What about members who already have weak passwords?

Check their password at the next sign-in and ask them to choose a new one if it is common or leaked. Offer two-step sign-in at the same time.

Keep going