mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Put a hard limit on password login attempts from the same remote address
Summary: Ref T13222. Currently, if a remote address fails a few login attempts (5) in a short period of time (15 minutes) we require a CAPTCHA for each additional attempt. This relies on: - Administrators configuring ReCAPTCHA, which they may just not bother with. - Administrators being comfortable with Google running arbitrary trusted Javascript, which they may not be comfortable with. - ReCAPTCHA actually being effective, which seems likely true for unsophisticated attackers but perhaps less true for more sophisticated attackers (see <https://github.com/ecthros/uncaptcha2>, for example). (For unsophisticated attackers and researchers, "Rumola" has been the standard CAPTCHA bypass tool for some time. This is an extension that pays humans to solve CAPTCHAs for you. This is not practical at "brute force a strong password" scale. Google appears to have removed it from the Chrome store. The "submit the captcha back to Google's APIs" trick probably isn't practical at brute-force-scale either, but it's easier to imagine weaponizing that than weaponizing human solvers.) Add a hard gate behind the CAPTHCA wall so that we fail into a secure state if there's no CAPTCHA or the attacker can defeat CAPTCHAs at a very low cost. The big downside to this is that an attacker who controls your remote address (e.g., is behind the same NAT device you're behind on corpnet) can lock you out of your account. However: - That //should// be a lot of access (although maybe this isn't that high of a barrier in many cases, since compromising a "smart fridge" or "smart water glass" or whatever might be good enough). - You can still do "Forgot password?" and login via email link, although this may not be obvious. Test Plan: - Logged in normally. - Failed many many login attempts, got hard gated. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13222 Differential Revision: https://secure.phabricator.com/D19997
This commit is contained in:
parent
c125ab7a42
commit
310ad7f8f4
1 changed files with 34 additions and 4 deletions
|
@ -255,18 +255,48 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
|
|||
$viewer = $request->getUser();
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
$captcha_limit = 5;
|
||||
$hard_limit = 32;
|
||||
$limit_window = phutil_units('15 minutes in seconds');
|
||||
|
||||
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
|
||||
PhabricatorUserLog::ACTION_LOGIN_FAILURE,
|
||||
$limit_window);
|
||||
|
||||
// If the same remote address has submitted several failed login attempts
|
||||
// recently, require they provide a CAPTCHA response for new attempts.
|
||||
$require_captcha = false;
|
||||
$captcha_valid = false;
|
||||
if (AphrontFormRecaptchaControl::isRecaptchaEnabled()) {
|
||||
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
|
||||
PhabricatorUserLog::ACTION_LOGIN_FAILURE,
|
||||
60 * 15);
|
||||
if (count($failed_attempts) > 5) {
|
||||
if (count($failed_attempts) > $captcha_limit) {
|
||||
$require_captcha = true;
|
||||
$captcha_valid = AphrontFormRecaptchaControl::processCaptcha($request);
|
||||
}
|
||||
}
|
||||
|
||||
// If the user has submitted quite a few failed login attempts recently,
|
||||
// give them a hard limit.
|
||||
if (count($failed_attempts) > $hard_limit) {
|
||||
$guidance = array();
|
||||
|
||||
$guidance[] = pht(
|
||||
'Your remote address has failed too many login attempts recently. '.
|
||||
'Wait a few minutes before trying again.');
|
||||
|
||||
$guidance[] = pht(
|
||||
'If you are unable to log in to your account, you can '.
|
||||
'[[ /login/email | send a reset link to your email address ]].');
|
||||
|
||||
$guidance = implode("\n\n", $guidance);
|
||||
|
||||
$dialog = $controller->newDialog()
|
||||
->setTitle(pht('Too Many Login Attempts'))
|
||||
->appendChild(new PHUIRemarkupView($viewer, $guidance))
|
||||
->addCancelButton('/auth/start/', pht('Wait Patiently'));
|
||||
|
||||
return array(null, $dialog);
|
||||
}
|
||||
|
||||
$response = null;
|
||||
$account = null;
|
||||
$log_user = null;
|
||||
|
|
Loading…
Reference in a new issue