r70520 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70519‎ | r70520 | r70521 >
Date:19:16, 5 August 2010
Author:maxsem
Status:reverted (Comments)
Tags:
Comment:
JavaScript-based password complexity checker on account creation and password change. Needs attention from CSS gurus to look decently.
Note that OutputPage::addPasswordSecurity() doesn't check the enabling setting to make this code reusable by extensions who don't always want to follow core settings.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/OutputPage.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialResetpass.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialUserlogin.php (modified) (history)
  • /trunk/phase3/includes/templates/Userlogin.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -466,6 +466,13 @@
467467 'loginlanguagelabel',
468468 'loginlanguagelinks',
469469 'suspicious-userlogout',
 470+ 'password-strength',
 471+ 'password-strength-bad',
 472+ 'password-strength-mediocre',
 473+ 'password-strength-acceptable',
 474+ 'password-strength-good',
 475+ 'password-retype',
 476+ 'password-retype-mismatch',
470477 ),
471478 'resetpass' => array(
472479 'resetpass',
Index: trunk/phase3/includes/OutputPage.php
@@ -1955,6 +1955,22 @@
19561956 }
19571957 }
19581958
 1959+ public function addPasswordSecurity( $passwordId, $retypeId ) {
 1960+ $data = array(
 1961+ 'password' => '#' . $passwordId,
 1962+ 'retype' => '#' . $retypeId,
 1963+ 'messages' => array(),
 1964+ );
 1965+ foreach ( array( 'password-strength', 'password-strength-bad', 'password-strength-mediocre',
 1966+ 'password-strength-acceptable', 'password-strength-good', 'password-retype', 'password-retype-mismatch'
 1967+ ) as $message ) {
 1968+ $data['messages'][$message] = wfMsg( $message );
 1969+ }
 1970+ $this->addScript( Html::inlineScript( 'var passwordSecurity=' . FormatJSON::encode( $data ) ) );
 1971+ $this->addScriptFile( 'password.js' );
 1972+ $this->addStyle( 'common/password.css' );
 1973+ }
 1974+
19591975 /** @deprecated */
19601976 public function errorpage( $title, $msg ) {
19611977 wfDeprecated( __METHOD__ );
Index: trunk/phase3/includes/DefaultSettings.php
@@ -1556,7 +1556,7 @@
15571557 * to ensure that client-side caches do not keep obsolete copies of global
15581558 * styles.
15591559 */
1560 -$wgStyleVersion = '299';
 1560+$wgStyleVersion = '300';
15611561
15621562 /**
15631563 * This will cache static pages for non-logged-in users to reduce
@@ -5115,6 +5115,11 @@
51165116 $wgUploadMaintenance = false;
51175117
51185118 /**
 5119+ * Enabes or disables JavaScript-based suggestions of password strength
 5120+ */
 5121+$wgLivePasswordStrengthChecks = true;
 5122+
 5123+/**
51195124 * For really cool vim folding this needs to be at the end:
51205125 * vim: foldmarker=@{,@} foldmethod=marker
51215126 * @}
Index: trunk/phase3/includes/specials/SpecialUserlogin.php
@@ -968,6 +968,10 @@
969969 $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
970970
971971 if ( $this->mType == 'signup' ) {
 972+ global $wgLivePasswordStrengthChecks;
 973+ if ( $wgLivePasswordStrengthChecks ) {
 974+ $wgOut->addPasswordSecurity( 'wpPassword2', 'wpRetype' );
 975+ }
972976 $template = new UsercreateTemplate();
973977 $q = 'action=submitlogin&type=signup';
974978 $linkq = 'type=login';
Index: trunk/phase3/includes/specials/SpecialResetpass.php
@@ -106,8 +106,11 @@
107107 }
108108
109109 function showForm() {
110 - global $wgOut, $wgUser, $wgRequest;
 110+ global $wgOut, $wgUser, $wgRequest, $wgLivePasswordStrengthChecks;
111111
 112+ if ( $wgLivePasswordStrengthChecks ) {
 113+ $wgOut->addPasswordSecurity( 'wpNewPassword', 'wpRetype' );
 114+ }
112115 $self = $this->getTitle();
113116 if ( !$this->mUserName ) {
114117 $this->mUserName = $wgUser->getName();
@@ -143,10 +146,10 @@
144147 wfMsgExt( 'resetpass_text', array( 'parse' ) ) . "\n" .
145148 Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" .
146149 $this->pretty( array(
147 - array( 'wpName', 'username', 'text', $this->mUserName ),
148 - array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ),
149 - array( 'wpNewPassword', 'newpassword', 'password', null ),
150 - array( 'wpRetype', 'retypenew', 'password', null ),
 150+ array( 'wpName', 'username', 'text', $this->mUserName, '' ),
 151+ array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass, '' ),
 152+ array( 'wpNewPassword', 'newpassword', 'password', null, '<div id="password-strength"></div>' ),
 153+ array( 'wpRetype', 'retypenew', 'password', null, '<div id="password-retype"></div>' ),
151154 ) ) . "\n" .
152155 $rememberMe .
153156 "<tr>\n" .
@@ -165,7 +168,7 @@
166169 function pretty( $fields ) {
167170 $out = '';
168171 foreach ( $fields as $list ) {
169 - list( $name, $label, $type, $value ) = $list;
 172+ list( $name, $label, $type, $value, $extra ) = $list;
170173 if( $type == 'text' ) {
171174 $field = htmlspecialchars( $value );
172175 } else {
@@ -186,9 +189,8 @@
187190 else
188191 $out .= wfMsgHtml( $label );
189192 $out .= "</td>\n";
190 - $out .= "\t<td class='mw-input'>";
191 - $out .= $field;
192 - $out .= "</td>\n";
 193+ $out .= "\t<td class='mw-input'>$field</td>\n";
 194+ $out .= "\t<td>$extra</td>\n";
193195 $out .= "</tr>";
194196 }
195197 return $out;
Index: trunk/phase3/includes/templates/Userlogin.php
@@ -169,6 +169,7 @@
170170 'autofocus'
171171 ) ); ?>
172172 </td>
 173+ <td></td>
173174 </tr>
174175 <tr>
175176 <td class="mw-label"><label for='wpPassword2'><?php $this->msg('yourpassword') ?></label></td>
@@ -181,6 +182,7 @@
182183 'size' => '20'
183184 ) + User::passwordChangeInputAttribs() ); ?>
184185 </td>
 186+ <td><div id="password-strength"></div></td>
185187 </tr>
186188 <?php if( $this->data['usedomain'] ) {
187189 $doms = "";
@@ -196,6 +198,7 @@
197199 <?php echo $doms ?>
198200 </select>
199201 </td>
 202+ <td></td>
200203 </tr>
201204 <?php } ?>
202205 <tr>
@@ -209,6 +212,7 @@
210213 'size' => '20'
211214 ) + User::passwordChangeInputAttribs() ); ?>
212215 </td>
 216+ <td><div id="password-retype"></div></td>
213217 </tr>
214218 <tr>
215219 <?php if( $this->data['useemail'] ) { ?>
@@ -229,12 +233,13 @@
230234 } ?>
231235 </div>
232236 </td>
 237+ <td></td>
233238 <?php } ?>
234239 <?php if( $this->data['userealname'] ) { ?>
235240 </tr>
236241 <tr>
237242 <td class="mw-label"><label for='wpRealName'><?php $this->msg('yourrealname') ?></label></td>
238 - <td class="mw-input">
 243+ <td class="mw-input" colspan="2">
239244 <input type='text' class='loginText' name="wpRealName" id="wpRealName"
240245 tabindex="6"
241246 value="<?php $this->text('realname') ?>" size='20' />
@@ -242,12 +247,13 @@
243248 <?php $this->msgWiki('prefs-help-realname'); ?>
244249 </div>
245250 </td>
 251+ <td></td>
246252 <?php } ?>
247253 <?php if( $this->data['usereason'] ) { ?>
248254 </tr>
249255 <tr>
250256 <td class="mw-label"><label for='wpReason'><?php $this->msg('createaccountreason') ?></label></td>
251 - <td class="mw-input">
 257+ <td class="mw-input" colspan="2">
252258 <input type='text' class='loginText' name="wpReason" id="wpReason"
253259 tabindex="7"
254260 value="<?php $this->text('reason') ?>" size='20' />
@@ -257,7 +263,7 @@
258264 <?php if( $this->data['canremember'] ) { ?>
259265 <tr>
260266 <td></td>
261 - <td class="mw-input">
 267+ <td class="mw-input" colspan="2">
262268 <?php
263269 global $wgCookieExpiration, $wgLang;
264270 echo Xml::checkLabel(
@@ -285,7 +291,7 @@
286292 ?><td><?php
287293 }
288294 ?></td>
289 - <td class="mw-input">
 295+ <td class="mw-input" colspan="2">
290296 <input type="<?php echo htmlspecialchars( $inputItem['type'] ) ?>" name="<?php
291297 echo htmlspecialchars( $inputItem['name'] ); ?>"
292298 tabindex="<?php echo $tabIndex++; ?>"
@@ -320,7 +326,7 @@
321327 ?>
322328 <tr>
323329 <td></td>
324 - <td class="mw-submit">
 330+ <td class="mw-submit" colspan="2">
325331 <input type='submit' name="wpCreateaccount" id="wpCreateaccount"
326332 tabindex="<?php echo $tabIndex++; ?>"
327333 value="<?php $this->msg('createaccount') ?>" />
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1145,6 +1145,13 @@
11461146 * Italiano|it
11471147 * Nederlands|nl', # do not translate or duplicate this message to other languages
11481148 'suspicious-userlogout' => 'Your request to log out was denied because it looks like it was sent by a broken browser or caching proxy.',
 1149+'password-strength' => 'Estimated password strength: $1',
 1150+'password-strength-bad' => 'BAD',
 1151+'password-strength-mediocre' => 'mediocre',
 1152+'password-strength-acceptable' => 'acceptable',
 1153+'password-strength-good' => 'good',
 1154+'password-retype' => 'Retype password here',
 1155+'password-retype-mismatch' => 'Passwords don\'t match',
11491156
11501157 # Password reset dialog
11511158 'resetpass' => 'Change password',
Index: trunk/phase3/RELEASE-NOTES
@@ -132,7 +132,8 @@
133133 ** (bug 1211) Subcategories, ordinary pages, and files now page separately.
134134 ** When several pages are given the same sort key, they sort by their names
135135 instead of randomly.
136 -* (bug 23848) Add {{ARTICLEPATH}} Magic Word
 136+* JavaScript-based password complexity checker on account creation and
 137+ password change.
137138
138139 === Bug fixes in 1.17 ===
139140 * (bug 17560) Half-broken deletion moved image files to deletion archive

Follow-up revisions

RevisionCommit summaryAuthorDate
r70521Follow-up to r70520: forgot to add new filesmaxsem19:18, 5 August 2010
r70522Restored line accidentally removed in r70520maxsem19:21, 5 August 2010
r70527Message and formatting tweaks for r70520siebrand20:50, 5 August 2010
r70528Message and formatting tweaks for r70520. Forgot to commit this in r70527.siebrand21:17, 5 August 2010
r70536Follow up r70520. More for loop fixes.hartman01:24, 6 August 2010
r70769Fixes for password checker from r70520:...maxsem16:17, 9 August 2010
r70961Follow up r70520. Use canonical class name.platonides14:37, 12 August 2010
r814451.17: Take out r70520 (JS password strength checker)catrope12:24, 3 February 2011
r86157Merge r81445 from 1.17: revert r70520 (js password complexity checker)demon23:38, 15 April 2011
r101520Bug 32125: remove stray $wgLivePasswordStrengthChecks leftover from a reverte...brion20:17, 1 November 2011

Comments

#Comment by Nikerabbit (talk | contribs)   19:39, 5 August 2010

Yay great stuff. Few issues:

  • Display is quite ugly (due to layout)
  • Reports everything as BAD for me
  • I don't see the need for a global for this one.
#Comment by MZMcBride (talk | contribs)   20:18, 5 August 2010

I don't know for sure, but I'm assuming that this revision is related to this Signpost piece.

I find the entire idea that you need to be told how strong your password should be for your encyclopedia-editing account to be a bit extreme. It may make some sense for accounts with elevated user rights, but I think this is bad nannying when applied to all users.

#Comment by MaxSem (talk | contribs)   20:19, 5 August 2010

Yes, it gave me the idea.

#Comment by Simetrical (talk | contribs)   20:17, 8 August 2010

I don't think we should have any such password-checker for ordinary users. Ordinary user accounts can do nothing bad if compromised, we should not be trying to scare them into using harder-to-remember passwords. Security vs. convenience falls on the side of convenience here.

If actual password security is desired, it should use an existing well-established system, not a crude one made up by us. Your system rates "password123" as "acceptable", but "mfkropl" as "BAD", although the latter is much less guessable than the former. It labels two of the three most common passwords according to <http://www.whatsmypass.com/the-top-500-worst-passwords-of-all-time> "mediocre" rather than "BAD" ("password" and "12345678"). It also seems to assume that nobody uses anything other than ASCII for passwords, which is totally unreasonable. This kind of pseudo-security is just annoying.

Some people might want this kind of silly thing, but I strongly feel that it should be off by default and off on all Wikimedia sites, or preferably relegated to an extension. A much better solution is to use a proper password security checker and make it mandatory for sysops, including prohibiting the promotion of a user to sysop if they don't have a secure enough password.

#Comment by Platonides (talk | contribs)   21:50, 8 August 2010

Ordinary users don't like being compromised more than others. For many people it's an online identity. We could approximate the damage it would do based on account age and activity, but that's unknown when creating the account. I think a good compromise is to show a password strength meter (without enforcing) and recommend using passwords moderate to high (instead of just high).

The problem is on measuring the password strength. As I asked on irc, I'd like to see documented how is it being measured, so that it can be analysed without going down to the code. Ideally, someone would have already studied the problem and we would only need to code the conclusions from a paper.

#Comment by Simetrical (talk | contribs)   22:05, 8 August 2010

Having your account compromised is extremely unlikely, but forgetting your password is common. Both can result in loss of access to the account. We should be encouraging ordinary users to use easy-to-remember (thus probably easy to guess) passwords to reduce the high risk of forgetting passwords, rather than encouraging them to use hard-to-guess (thus probably hard to remember) passwords to reduce the extremely tiny risk of someone trying to guess your password. Someone guessing your password is particularly unlikely for non-admins, since there's no obvious motive, and hackers almost always have a motive.

#Comment by Platonides (talk | contribs)   22:11, 8 August 2010

We should encourage providing an email instead. We can recommend password stores, too.


> Someone guessing your password is particularly unlikely for non-admins, since there's no obvious motive, and hackers almost always have a motive.

  1. You are an admin on a different wiki.
  2. It is a private wiki.
  3. You have 99 positive votes for becoming an admin.
  4. You can approve Good Articles / Flickr licenses...
  5. You tagged my article for deletion!! (I have seen big reactions for the dumbest "articles")


Anyway, the conditions under which the strength meter would be shown are somehting to be defined separatedly.

#Comment by Simetrical (talk | contribs)   15:16, 9 August 2010

Confirming an e-mail is a pain, and many people change their e-mail address every few years (moving to different providers, changing name, etc.). People also might not want to give their e-mail to avoid spam.

I don't object to having a strength meter somewhere, as long as it doesn't use really stupid heuristics (which 98% of password strength meters do), but I strongly feel it should be off by default for all users, and off on Wikimedia for new users.

#Comment by 😂 (talk | contribs)   15:19, 9 August 2010

What about putting it on Special:ResetPassword but not on the sign-up screen? It would keep us from being off-putting to people signing up, but still allow for suggestions/strength feedback when they're changing their password.

Agree 100% that it should be based on good heuristics.

#Comment by Simetrical (talk | contribs)   15:21, 9 August 2010

If it's reasonably pretty and unobtrusive and uses smart heuristics, then maybe that would be okay. None of those three conditions hold right now, though, so it should still be disabled by default until then. We should not be jumping on security-theater bandwagons that don't actually benefit our users more than annoy them.

#Comment by Nikerabbit (talk | contribs)   15:24, 9 August 2010

Don't you have a bit extreme position here? If they think wmf is going to send spam, they are probably also going to use strong passwords. Regardless, we are not forcing anything here, just giving user a good feeling and confidence if they happen to choose a good password. And yes the meter should be fixed (it's broken like I said above) and the heuristics should be made more appropriate.

#Comment by Simetrical (talk | contribs)   22:02, 12 August 2010

I just don't think we should encourage regular users to use strong passwords at all. They should use weak, easy-to-remember passwords in preference to strong, hard-to-remember passwords. The risk of forgetting their password is much greater than the risk of someone else guessing their password, and the two scenarios are equivalently damaging (loss of access to account, no real damage done). Putting up a password strength meter encourages users to choose strong, hard-to-remember passwords, which is bad in the case of Wikipedia. Having your account compromised is only worse than forgetting your password when the attacker can cause damage or view private information, and that's not the case on normal wikis.

#Comment by Platonides (talk | contribs)   19:52, 9 August 2010

Note that you don't need to confirm the email for password reset, only to use Special:EmailUser.

#Comment by Preibusch (talk | contribs)   13:24, 9 August 2010

It may not be the best available solution, but it is documented and deployed: Microsoft Password checker <http://www.microsoft.com/uk/protect/yourself/password/checker.mspx>, with underlying design choices <http://www.microsoft.com/uk/protect/yourself/password/create.mspx>. This implementation differs from the one currently deployed on live.com. Also, neither of these two flag passwords made up of sequences of adjacent keys (e.g. "1qaz2wsx").

#Comment by Platonides (talk | contribs)   13:51, 9 August 2010

They are tips more than a documentation, but useful as well.

A shortcoming of that password checker (which is quite common) is that it considers "123456$a" as strong but "ryfewtyajfyknelzqthhbhbxfckxrxyesamwemuugkhzrvkfepzdmrpmfyleaoktjzxusmbvtweixrfz" weak whereas the first has about 6.5536e+12 (408) bits of entropy and the second 1.57713125193e+113 (2680)

#Comment by MaxSem (talk | contribs)   05:28, 26 January 2011

Meh, let's just not include this in 1.17.

#Comment by Catrope (talk | contribs)   21:27, 2 February 2011

I tried taking it out of 1.17, but it's getting kind of annoying, so I'd rather just leave it in and leave it disabled by default.

#Comment by Catrope (talk | contribs)   12:26, 3 February 2011

...is what I said when I was almost falling asleep on my keyboard. 11 hours of sleep later, it was actually fairly easy. Taken out of 1.17 in r81445.

Status & tagging log