mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Add a common password blacklist
Summary: Fixes T4143. This mitigates the "use a botnet to slowly try to login to every user account using the passwords '1234', 'password', 'asdfasdf', ..." attack, like the one that hit GitHub. (I also donated some money to Openwall as a thanks for compiling this wordlist.) Test Plan: - Tried to register with a weak password; registered with a strong password. - Tried to set VCS password to a weak password; set VCS password to a strong password. - Tried to change password to a weak password; changed password to a strong password. Reviewers: btrahan Reviewed By: btrahan CC: aran, chad Maniphest Tasks: T4143 Differential Revision: https://secure.phabricator.com/D8048
This commit is contained in:
parent
1a964f71bb
commit
02aa193cb0
7 changed files with 3670 additions and 4 deletions
15
externals/wordlist/LICENSE.txt
vendored
Normal file
15
externals/wordlist/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
The following copyright statement applies to this wordlists collection as a whole:
|
||||||
|
Copyright (c) 2002,2003 by Solar Designer of Openwall Project
|
||||||
|
|
||||||
|
The homepage URL for this wordlists collection is:
|
||||||
|
|
||||||
|
http://www.openwall.com/wordlists/
|
||||||
|
|
||||||
|
You're allowed to use and redistribute this wordlists collection or parts thereof, with or without modification, provided that credit is given where it is due, any modified versions are marked as such, this license is kept intact and included with each copy, and NO FEE IS CHARGED FOR OBTAINING A COPY except as negotiated with the copyright holder. In particular, you are NOT permitted to charge for bandwidth, physical media, and/or shipping. You're also not permitted to bundle this wordlists collection with a product you charge for.
|
||||||
|
|
||||||
|
If redistribution for a fee is what you're after, please contact the copyright holder to negotiate special terms for the downloadable or the extended CD-ready version of this collection.
|
||||||
|
|
||||||
|
It was a significant amount of work to compile this collection and having a monopoly on regulating the CD sales is my way to compensate for the time already spent and to allow for further work.
|
||||||
|
|
||||||
|
--
|
||||||
|
Alexander Peslyak aka Solar Designer <solar at openwall.com>
|
3557
externals/wordlist/password.lst
vendored
Normal file
3557
externals/wordlist/password.lst
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1267,6 +1267,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php',
|
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php',
|
||||||
'PhabricatorChatLogEventType' => 'applications/chatlog/constants/PhabricatorChatLogEventType.php',
|
'PhabricatorChatLogEventType' => 'applications/chatlog/constants/PhabricatorChatLogEventType.php',
|
||||||
'PhabricatorChatLogQuery' => 'applications/chatlog/PhabricatorChatLogQuery.php',
|
'PhabricatorChatLogQuery' => 'applications/chatlog/PhabricatorChatLogQuery.php',
|
||||||
|
'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php',
|
||||||
'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php',
|
'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php',
|
||||||
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php',
|
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php',
|
||||||
'PhabricatorConduitConfigOptions' => 'applications/conduit/config/PhabricatorConduitConfigOptions.php',
|
'PhabricatorConduitConfigOptions' => 'applications/conduit/config/PhabricatorConduitConfigOptions.php',
|
||||||
|
@ -3869,6 +3870,7 @@ phutil_register_library_map(array(
|
||||||
),
|
),
|
||||||
'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants',
|
'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants',
|
||||||
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorCommonPasswords' => 'Phobject',
|
||||||
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
||||||
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
|
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
|
||||||
'PhabricatorConduitConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorConduitConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a password is extremely common. Preventing use of the most common
|
||||||
|
* passwords is an attempt to mitigate slow botnet attacks against an entire
|
||||||
|
* userbase. See T4143 for discussion.
|
||||||
|
*
|
||||||
|
* @task common Checking Common Passwords
|
||||||
|
*/
|
||||||
|
final class PhabricatorCommonPasswords extends Phobject {
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Checking Common Passwords )------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a password is extremely common.
|
||||||
|
*
|
||||||
|
* @param string Password to test.
|
||||||
|
* @return bool True if the password is pathologically weak.
|
||||||
|
*
|
||||||
|
* @task common
|
||||||
|
*/
|
||||||
|
public static function isCommonPassword($password) {
|
||||||
|
static $list;
|
||||||
|
if ($list === null) {
|
||||||
|
$list = self::loadWordlist();
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($list[strtolower($password)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the common password wordlist.
|
||||||
|
*
|
||||||
|
* @return map<string, bool> Map of common passwords.
|
||||||
|
*
|
||||||
|
* @task common
|
||||||
|
*/
|
||||||
|
private static function loadWordlist() {
|
||||||
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
$file = $root.'/externals/wordlist/password.lst';
|
||||||
|
$data = Filesystem::readFile($file);
|
||||||
|
|
||||||
|
$words = phutil_split_lines($data, $retain_endings = false);
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($words as $key => $word) {
|
||||||
|
// The wordlist file has some comments at the top, strip those out.
|
||||||
|
if (preg_match('/^#!comment:/', $word)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$map[strtolower($word)] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in some application-specific passwords.
|
||||||
|
$map += array(
|
||||||
|
'phabricator' => true,
|
||||||
|
'phab' => true,
|
||||||
|
'devtools' => true,
|
||||||
|
'differential' => true,
|
||||||
|
'codereview' => true,
|
||||||
|
'review' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -182,6 +182,14 @@ final class PhabricatorAuthRegisterController
|
||||||
$errors[] = pht(
|
$errors[] = pht(
|
||||||
'Password is too short (must be at least %d characters long).',
|
'Password is too short (must be at least %d characters long).',
|
||||||
$min_len);
|
$min_len);
|
||||||
|
} else if (
|
||||||
|
PhabricatorCommonPasswords::isCommonPassword($value_password)) {
|
||||||
|
|
||||||
|
$e_password = pht('Very Weak');
|
||||||
|
$errors[] = pht(
|
||||||
|
'Password is pathologically weak. This password is one of the '.
|
||||||
|
'most common passwords in use, and is extremely easy for '.
|
||||||
|
'attackers to guess. You must choose a stronger password.');
|
||||||
} else {
|
} else {
|
||||||
$e_password = null;
|
$e_password = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,19 @@ final class DiffusionSetPasswordPanel extends PhabricatorSettingsPanel {
|
||||||
$e_password = pht('Not Unique');
|
$e_password = pht('Not Unique');
|
||||||
$e_confirm = pht('Not Unique');
|
$e_confirm = pht('Not Unique');
|
||||||
$errors[] = pht(
|
$errors[] = pht(
|
||||||
'This password is not unique. You must use a unique password.');
|
'This password is the same as another password associated '.
|
||||||
|
'with your account. You must use a unique password for '.
|
||||||
|
'VCS access.');
|
||||||
|
} else if (
|
||||||
|
PhabricatorCommonPasswords::isCommonPassword($new_password)) {
|
||||||
|
$e_password = pht('Very Weak');
|
||||||
|
$e_confirm = pht('Very Weak');
|
||||||
|
$errors[] = pht(
|
||||||
|
'This password is extremely weak: it is one of the most common '.
|
||||||
|
'passwords in use. Choose a stronger password.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
$vcspassword->setPassword($envelope, $user);
|
$vcspassword->setPassword($envelope, $user);
|
||||||
$vcspassword->save();
|
$vcspassword->save();
|
||||||
|
|
|
@ -75,11 +75,15 @@ final class PhabricatorSettingsPanelPassword
|
||||||
if (strlen($pass) < $min_len) {
|
if (strlen($pass) < $min_len) {
|
||||||
$errors[] = pht('Your new password is too short.');
|
$errors[] = pht('Your new password is too short.');
|
||||||
$e_new = pht('Too Short');
|
$e_new = pht('Too Short');
|
||||||
}
|
} else if ($pass !== $conf) {
|
||||||
|
|
||||||
if ($pass !== $conf) {
|
|
||||||
$errors[] = pht('New password and confirmation do not match.');
|
$errors[] = pht('New password and confirmation do not match.');
|
||||||
$e_conf = pht('Invalid');
|
$e_conf = pht('Invalid');
|
||||||
|
} else if (PhabricatorCommonPasswords::isCommonPassword($pass)) {
|
||||||
|
$e_new = pht('Very Weak');
|
||||||
|
$e_conf = pht('Very Weak');
|
||||||
|
$errors[] = pht(
|
||||||
|
'Your new password is very weak: it is one of the most common '.
|
||||||
|
'passwords in use. Choose a stronger password.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
|
|
Loading…
Reference in a new issue