Page MenuHomePhabricator

New extension to enforce minimum password strength.
Closed, ResolvedPublic

Description

Author: mike.lifeguard+bugs

Description:
Apparently Brion ran at least once a "password cracker" (http://meta.wikimedia.org/wiki/Talk:Stewards#Proposed_security_policy). While that's useful to identify vulnerable accounts, it is perhaps best to enforce minimum password strength from the get-go.

This extension should have the ability to

  • force users to reset their password every X timespan
  • T27925 enforce minimum password length
  • T46788 enforce varying levels of password security by user group (ie admins have an intermediate level, stewards must have a high level)
  • T11838 Send notification to account owner on multiple unsuccessful login attempts
  • maybe other stuff I've not thought about

Version: unspecified
Severity: enhancement
See Also:
T46788: Allow different password requirements by group
T27925: Increase $wgMinimalPasswordLength

Details

Reference
bz16435

Event Timeline

bzimport raised the priority of this task from to Medium.Nov 21 2014, 10:27 PM
bzimport set Reference to bz16435.
bzimport added a subscriber: Unknown Object (MLST).

Note: Minimal password lenght is already configurable with $wgMinimalPasswordLength (http://www.mediawiki.org/wiki/Manual:$wgMinimalPasswordLength).

mike.lifeguard+bugs wrote:

(In reply to comment #1)

Note: Minimal password lenght is already configurable with
$wgMinimalPasswordLength
(http://www.mediawiki.org/wiki/Manual:$wgMinimalPasswordLength).

Yes, but this should verify password /strength/

For example, on the toolserver, you cannot set a password with dictionary words (longer than X chars, I think), and you must include 3 of 4 character classes or something (lower case, uppercase, numbers, special chars...?). And so on (presumably the programmers know better than I do what makes a strong password).

(In reply to comment #2)

Yes, but this should verify password /strength/

For example, on the toolserver, you cannot set a password with dictionary words
(longer than X chars, I think), and you must include 3 of 4 character classes
or something (lower case, uppercase, numbers, special chars...?). And so on
(presumably the programmers know better than I do what makes a strong
password).

Since there's a captcha after 3 attempts and a temporary lockout after 3 (or so) more attempts, I'm not sure if it's a good idea to enforce that much brute force or dictionary resistant passwords.
Too strong passwords would be difficult for the users to remember.
What about just letting the user know about his/her password strength ?

However, since the compromised accounts passwords were either the same as the login or just "password", those are basic rules to improve password strength (they are probably already active).

mike.lifeguard+bugs wrote:

(In reply to comment #3)

Since there's a captcha after 3 attempts and a temporary lockout after 3 (or
so) more attempts, I'm not sure if it's a good idea to enforce that much brute
force or dictionary resistant passwords.
Too strong passwords would be difficult for the users to remember.
What about just letting the user know about his/her password strength ?

Yes, that'd be nice too. I know of several sites which have a password strengh indicator beside the input which changes as you're typing from "empty" in grey -> "weak" in red -> "OK" in yellow -> "strong" in green using AJAX.

However, since the compromised accounts passwords were either the same as the
login or just "password", those are basic rules to improve password strength
(they are probably already active).

I'm not sure what you mean here... Are there already restrictions on using "password" as the password, or using your username as the password? That good, but we can do better.

Fwiw, I've already got an extension in SVN (PasswordStrength) that requires some heuristics on changing password.

Maybe the features described here could be incorporated?

(In reply to comment #4)

(In reply to comment #3)

Since there's a captcha after 3 attempts and a temporary lockout after 3 (or
so) more attempts, I'm not sure if it's a good idea to enforce that much brute
force or dictionary resistant passwords.
Too strong passwords would be difficult for the users to remember.
What about just letting the user know about his/her password strength ?

Yes, that'd be nice too. I know of several sites which have a password strengh
indicator beside the input which changes as you're typing from "empty" in grey
-> "weak" in red -> "OK" in yellow -> "strong" in green using AJAX.

It could even be done by JavaScript only, by the way (unless we check against a dictionary).

However, since the compromised accounts passwords were either the same as the
login or just "password", those are basic rules to improve password strength
(they are probably already active).

I'm not sure what you mean here... Are there already restrictions on using
"password" as the password, or using your username as the password? That good,
but we can do better.

I mean that we should just require passwords different from the username, and forbid passwords like "password" or so.
Requiring very strong passwords (like letters + numbers) would be an unnecessary annoyance for the user.

I think between those two things we can call this FIXED.

Issues or enhancements with either should go as their own bugs.

This bug doesn't feel fixed to me. In particular, this piece:

(In reply to comment #0)

  • enforce varying levels of password security by user group (ie admins have an

intermediate level, stewards must have a high level)

doesn't appear to have been addressed. Re-opening for now.

I've opened bug 44788 so we can specifically track that issue.

It's currently sort of in SecurePasswords, though there is no component for that.

Tgr set Security to None.
Tgr claimed this task.
Tgr subscribed.

*force users to reset their password every X timespan
*enforce minimum password length
*enforce varying levels of password security by user group (ie admins have an intermediate level, stewards must have a high level)

All of this is in core now (via $wgPasswordPolicy) and notifications and the strength meter have their own tasks (T11838, T32574).

Note: "minimum password length" should not be measured in terms of number of characters, but in number of strength bits per character. Forcing users to use a mix of for example 1 letter, 1 digit, 1 punctuation with an 8 characters limit means that you'll reduce the full strength offered by a complete 8 characters limit.

Goal

The goal is to increase the search space against brute force attacks, but not to reduce the choice of passwords by excluding some combinations.

We can create an algorithm to evaluate this bit strength but it must be smarter than just a number of characters, it can check for other characteristics (and must not be restricted to only ASCII, as users will benefit if they use passwords or passphrases containing non-ASCII characters, possibly in multiple scripts (e.g. Latin+Cyrillic or Kana+Kanji), including uncommon punctuations (e.g. CJK punctuation for those users contributing in Chinese, Japanese or Korean and that conveniently have these characters on their keyboards)

Designing an algorithm for evaluating password strength

  • Take the punctuations, most users will just use a few of them in a small set (",.;:!_*/'"@+-_" and space) whose bitstrength is low in this set, but some punctuations are uncommon and have higher bit strengths (notably those outside ASCII).
  • Take the letters: using lowercase only reduced the search space to one 26 letters, but allowing capital letters will set the search space to 52 letters, and users using any mix of lowercase and uppercase letters will have a password with higher bitstrength (any change of lettercase in the password counts for one additional bit). Lowercase only letters are estimated to 4 bits of strength per letter, same thing for uppercase letters, but allowing both cases means that we add 1 bit for each lettercase change (ignore other non-letter characters between them) plus one bit for the first letter.
  • Take the digits: there are only 10 of them and each digits counts for only 3.3 bits (=log2(10)); if we add non-ASCII digits (e.g. CJK fullwidth digits or Arabic digits) they'll each have a higher bitstrength.
  • Consider non-ASCII characters: they are encoded as UTF-8 using multiple bytes. The leading byte of UTF-8-encoded characters (0xC4...) has a lower strength (2 bits at most) than trailing bytes (0xA0..0xBF, each counting for about 4 bits of strength)
  • A dictionnary lookup for common terms (in a dictionnary containing about 256 entries) means that the password has only 7 bits of strength. Using passphrases containing these terms (e.g. 2 terms and a punctuation) would bring a minimum strength of 7+3+7 bits, i.e. only 17 bits, which is still not enough to get a good strength against bruteforce attacks based on dictionnaries. So computing the strength from a dictionnary lookup should qualify each term in the dictionnary with a bitcount (very low for terms like "pass", or "0000", or "1234", not exceeding about 2 bits)
  • Repeated subpatterns of characters: for each minimal repeated sequence of characters, evaluate the bit strength of this subpattern: only the first occurence counts for the bit strength total, all other occurences are counted as a total of: log2(number of occurences)+the sum of log2(distance between the last character of a pattern occurence to the next occurence)
  • Other test methods may be added to evaluate the strength depending on discoveries about occuring attacks.
  • As well the dictionnary used for this evaluation may need to be updated frequently
  • This dictionnary it could also include a automatically created selection of globally-uncommon terms that are used on public talk pages owned by the user, such as person names, pet names, birth dates and anniversaries, names of their friends and family members, phone numbers, "private" email addresses, city of residence... or some known account names on other sites or talk channels, as seen on their public user page: these detected terms should be visible to users to inform them not to use them in their passwords (these words found in chosen passwords would have a low bitstrength mesurement contributing to the total).

Using the bitstrength measurement and assigning strength classes

This measurement of strength (in bits) can then be transformed in the GUI by showing a graphical gauge and a summary class: "Low/insufficient", "Average", "Medium", "Strong", "Very strong": depending only on the computed bitstrength.

The minimum number of bits for each class can be reviewed form time to time, but forcing all users to type veryu long passwords using a reduced set of characters will be badly seen by users (that can't remember long sequences, unless they use some strong password generator tools and password wallet in their browser: there are several tools available the web to do it, and they are offer working across platforms: PCs on Windows/MacOS/Linux, mobiles/tablets on iOS/Android/Windows, some of them also working from other mobile platforms)

For usual accounts, we should force users to create their password with a minimum computed bitstrength of 32 bits, knowing that this strength will slowly degrade to 24 bits with age: under 28 bits, those users will loose some privileges, unless they take a new password regularly, or use longer/stronger passwords/passphrases, that won't cause the password to go below the minimum threshold after some reasonnaly long age to keep their privileges).

For our common security we should evaluate the minimum strength needed for each class: the wiki will internally record the bitstrength whe nthe password is generated, and some negative bits may be added depending on password age (e.g. substract up to 8 bits over one year).

For accounts with high privieges on wikis we could just require them to have a password shose total bitstrength (as generated minus the age) is in the "Strong class" (i.e. above the bitstrength minimum for that class).

Some very restricted privileges could require a minimum total bitstrength of 128 bits, including their negative strength caused by their age (or by the discovery that large amounts of passwords were stolen and published somewhere on the dark web: we should monitor these events when they are known or when we are alerted by CERT-like agencies).

The minimum of 128 bits for the "very strong" strength class could be reviewed later (gradually increased over time) if needed, by simple administration of password strength classes, just like all other strength classes we'll want to support for specific privileges.

Storing password strength

As the database will not store the clear passwords themselves, but only computed bitstrengths, sometimes this computed value may need to be reevaluated by upgrading the strength evaluation algorithm (e.g. after an update to the lookup dictionnary, or by implemetning new detections of too common patterns): if is possible that the same password will still have the same strength without renewing it: reconfiming the same password will reset their age to a maximum of 6 months, keeping some minimum age if it has not been really changed. If the user really changes his password, the age will be reset to 0.

What is then needed in user accounts : in addition to storing the encrypted/hashed password for the user, we just have to record two items:

  • the bitstrength (a floating point value expressed as a number of bits, i.e. the log2 of the estimated number of all possible passwords to check by brute force attacks or dictionnary attacks) as it was computed when it was changed and saved by the GUI used to evaluate the entered passwords;
  • a date of last change for knowing its age (so that we can compute negative bits, using simple linear arithmetic, and so that we can also notify users that it's time for them to change their password if they want to keep their strength class assignement before it is downgraded).

Displaying the password strength on the password change page

The GUI used for changing the password will then be able to display a label showing the pasword strength class (low, average, medium, strong, very strong), possibly on top of a visual gauge (a progress bar), and colors growing from red (low), orange (average), yellow (medium), green (strong), blue (very strong).

It will also be able to estimate when the password will need to be changed before its strength goes below the threshold for its displayed class (e.g. when it will go from "strong" to "average", or from "average" to "low/insufficient"). If the time before this threshold is reached is over 3 years, the GUI will not comment anything using inacurate predictions : it will just say "this password, currently considered strong, should remain strong for about 3 years")

Users may also receive notifications (by email if they've registered an email in their account) when their password threshold is about to go below the minimum threshols for its current strength class: it will be time for them to review their password online.

Administration of strength classes

Then separately we can administer the bitstrength thresholds for each class, and the speed of reduction (the negative bits per age time unit, and the maximum of bits that can be substracted from the stored computed bitstrength), and the minimum strength class needed for benefiting each privilege on the platforms (wikis, phabricator, labs, servers, SQL database accesses...).

HTTPS and security of the password strength evaluator

Of course the GUI used to enter passwords will need to use HTTPS, will probably need javascript (the evaluation of the bitstrengh should not be performed by the server that should not have access to the new cleartext password, it will just receive the encrypted/hashed value that the server will store "as is", but HTTPS is certainly desirable to secure the javascript code used for evaluating passwords and for encrypting/hashing them before submitting it with the input form).

Effectively, for privacy (and security) reasons, the password evaluator should run in the client context, without transmitting any cleartext password to the server.

However if the password change page is accessed exclusively via HTTPS, the server could optionally receive the cleartext password to evaluate its security itself, in order to defeat any possible hack on the client side by some local malwares trying to submit faked high values of the bitstrength.

But there will be privacy opposition/objections by users, even if the HTTPS connection to the server is encrypted (and not just authenticated), as external black hat agencies may still monitor what is submitted to the server, or because there may be security failures on the server side (unauthorized accesses by some third party or even by some bad administrators with authorizations to monitor this critical data submitted to the server).

For this reason this risk should be discussed: should the server be allowed to evaluate clear text password even if it will finally store only hashed/encrypted passwords ?

I can't decide it myself. In my opinion, the password evaluator should just run on the client side, to avoid many litigations with users.

Client-side security

We'll inform users connecting that this password evaluation will be running on the client side if they connect via HTTPS. they'll take themselves the responsability of securing their client against possible infections by spywares or malicious browser extensions.

We could also detect some browser extensions that are known to be unsecure, but activated on the client-side browser (some of these extensions are detectable in "User agent" strings, others may be detected using some home-made plugins such as Flash, Java, ActiveX, etc., or active scriptable audio/video plugins, or via some known vulnerabilities in client browsers which can be tested with wellknown libraries): and we'll inform users to use a more secure browser, or use their browser in "private mode" to disable all these detectable extensions, before using the password change page.

As well we could detect some known malicious VPNs or proxies used by clients trying to connect through them (notably if they connect to servers via HTTP and not with authenticated HTTPS). Some malicious "web accelerators" adverized on the web are in fact monitoring/logging all data that their users are sending thru them to the web, possibly with advanced filters to detet some patterns or some visited web pages (such as the password change page on Mediawiki).

Users not connecting via HTTPS

Users that can't or do not want to use HTTPS, will use a simpler form where the cleartext is sent to the server, but the server will evaulate it, and will add some negative bits immediately because the password change was not made over a secure connection: such password should also have their computed bitstrength capped to not reach any "strong" strength class, it would likely have only the current bitstrength of the "average" class and like all other passwords, this will be subject to age, with a slow degradation to "low/insufficient" after some months. This "average" class however should work for all users with registered accounts that can edit the wikis or submit/comment bugs in Phabricators, it will not be enough to work on servers, Labs, SQL servers, or to work as an admin on the wiki, or as a moderator.

Educating users to use stronger and distinct passwords

As we will display immediately to users our evaluation of the strength of their password, many of them will realize how much their password is unsecure and what they can do to choose better passwords/passphrases. We cannot however give a strong indication that their chosen password is really secure. Whatever they think, this strength may be in fact lower than what they expect using simple advices commonly advertized: many of them are still convinced that 8 characters or the addition of a few punctuation is enough to really secure their password against brute force attacks and dictionnary attacks).

When users will have reset their average passwords multiple times, they'll think that it's time for them to change for better/stronger passwords/passwords that will not deprecate so frequently: this will educate them without harassing them too often with needed password changes just to edit the wiki. They'll add a few characters or use better combinations, or they'll start using external tools (password managers) that generate very strong password that they no longer need to remember and type with difficulty.

Additionally, users are known to reuse the same password across a wide range of sites, many of them being now attacked and not securing their access passwords on them (the simplest way for an attacker to find the password used by a user is for tem to know that they also have accounts elsewhere, where the security is very low or inexistant and where their passwords may be stolen: attackers will include these discovered passwords in their dictionnary attacks against all other web sites used by the user, including our wikis and most of the time, they successfully connect with very few attempts even if the password was supposed to be "very strong")

We could also advertize on this password change page the existence of some free password managers they could use to generate very strong passwords and to assist them instead of remembering and typing these complex passwords with difficulty. Password managers help users using many distinct passwords for all their favorite websites: if a site is compomized, the "strong" password stolen there will not be usable on our wikis.

Only password managers allow users to use distinct strong passwords for many distinct sites. Some of them will also alert them when a site is compromized, so that they can also change their password there (this could be important if they use OAuth providers to connect to us: these external providers should have their own strong passwords).

Connecting via OAuth and evaluating strength of OAuth providers

If users can connect on Wikis using OAuth certificates, each OAuth provider should also have an assigned bitstrength (but no negative bits for age): this will allow wikis to manage OAuth sources if there's a known failure on them : a negative bitstrength will apply if the age is before the known date of vulnerability of that OAuth provider (if the OAuth provider has resolved the bug, all authentications made before that resolution date will have the negative bits set on them, there could be several dates in the history of that provider, with a growing number of negative strength bits for each date, if there was several vulnerabilities in that provider).

Additionally, if a user account is found on the Internet to have his password on the wiki or on the OAuth provider disclosed in an illegally stolen and published list, we could assign directly a large number of negative bits and the user will then be considered to have "low" strength passsword, until the user changes this password or reviews his password with the OAuth provider and confirms it by authenticating on the wiki with that provider (that will submit a new hash if it was really changed).

Could you consider structuring your last comment by providing sub headings? That might make it more likely that less people think <tl;dr>. Thanks for considering.

I just added some headings (in bold). I made some other corrections of typos, and restructured some paragraphs by reordering them.

I also added some more ideas for the algorithm to evaluate the password strength, and clarified some points.

Now that this message is dense, and is more a paper than a simple reply/comment, may be it could be made into some other public page or linked elsewhere for discussions. I expose the principles and possible objections. Not everything needs to be implemented immediately. There's certainly a need for experimentation and various tricky technical details to consider that I have certainly forgotten.

Anyway we are in an area where things are evolving/changing constantly. Attacks on the web are now occuring very frequently and are becoming very technical savvy using many advanced technics, and new breaches are constantly discovered against the passwords-only authentication methods.

Later we will probably need to use dual authentication systems via independant channels (but here also there are now some attacks, notably via the mobile SMS channel or phone calls, but the scale of success for these attacks are still low compared to attacks against single authentication methods; other attacks have occured on website that were previously considered very safe such as government sites or public services, such as social security or tax agencies, or even some police departments, national banks, the SWIFT interbank network, wellknown credit card providers, and wellknown online shops, gaming sites, and various local social networks).

@Verdy_p Hand rolling our own algorithm doesn't sound very great. IMHO a better idea, which is also easier, would just be to use zxcvbn.

It's built in JS, we can load it into the registration/change password page and display a live password strength meter; it even has feedback strings when you make common mistakes (may need some i18n).

And there is a php port, which could be used server side on login/register/change to store password strength data (score, crack times/entropy) and enforce minimum strength levels so you cannot register with a weak password and we can make sysop+ group rights unavailable when the stored password strength is below strong/some entropy level.

Oh well, so you have an algorithm, it just does the same kind of check so use it (it returns a score interms of log10 instead of log2() above, but this is equivalent at a scale factor of log(2)/log(10).

I tend to prefer log2 measures because it is directly related to common bit strengths in secure algorithms, such as the bit strength of all common hashes:

  • very strong hash algorithms whose result are limited to 128 bits are supposed to have a collision strength of up to 64 bits, not more, and no longer resistant enough against brute force attacks (they are not longer suitable for digitally signing PKI certificates).
  • very strong hashes algorithms today for authenticating accesses are typically now 512 bits (with a maximum collision strength of 256 bits) or more. They are used for signing PKI certificates.
  • encryption/decryption key pairs still typically use 128 bits in many commercial apps (they are just strong for privacy, but not suitable for keeping things really secret). Strong encryption keys use 512 or 1024 bits key pairs (the measurement of strength is also measured in terms of collisions with bulk-generated guesses to find correlation statistics with typical cleartext data.

The measurement in bits is easily comparable. And it has also a cute correlation with Moore's law (the increasing efficiency in terms of performance/cost that doubles every ~3 years due to evolution of techologies and reduction of construction/acquisition/usage costs and energy spent to run them): the bit strength allows estimating the time of resistance of old unchanged passwords with a reasonable prediction, it allows to notify users to change their password long before the strength becomes clearly insufficient for our common needs.

Note: the score and entropy are equivalent to log strengths (log2 for bit strengths, long10 with the zxcvbn algorithm) with just a constant factor. The crack time is a also proportional to the bit strength, roughly 3 years per bit above the 30-bit threshold (if there's no divulgation/spying of some cleartext and no discovered vulnerability reducing the bit strength with some kinds of easily reproductible collisions)

A single score in bits (as a floating point) is enough and then you can easily set minimum thresholds for the desired strength classes (how many bits of strength we need for strong or very strong passwords and below which number the strength is considered too low to be resistant to fast and cheap attacks).

The administration then just consistns in assigning the number of bits neacessary to reach the threashold to get a higher class. This administration will need to be reviewed regularly (adding 1 bit every 3 year for example to each class): classes are not immutable, they'll evolve even if passwords have not changed and their bit strength has not changed (because we've not updated the algorithm for the strength evaluator or its dictionnary).

Dictionnary-based scores will also evolve due to new wellknown social interactions (celebrities, movies/shows/song names, and evolution to the human languages with new fashioned terms or new wellknown trademarks, or other social/political events making some terms more famous than others). So dictionnary contents will also be updated (some sources for that can be the scores of hashtags in Twitter for example, or similar popularity scores in Facebook, search engines... that could inspire users trying to use these terms in their passwords/passphrases, and the introduction of neologisms, often borrowed from other languages)

Verdy_p updated the task description. (Show Details)