From 8f416baead93a48e5799e44b8bd2e2c4859f4e04 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Fri, 14 Sep 2007 13:18:58 +0200 Subject: auf Version 1.11 aktualisiert; Login-Bug behoben --- includes/api/ApiLogin.php | 139 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 7 deletions(-) (limited to 'includes/api/ApiLogin.php') diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php index 147d37a1..af68b29d 100644 --- a/includes/api/ApiLogin.php +++ b/includes/api/ApiLogin.php @@ -5,7 +5,8 @@ * * API for MediaWiki 1.8+ * - * Copyright (C) 2006 Yuri Astrakhan + * Copyright (C) 2006-2007 Yuri Astrakhan @gmail.com, + * Daniel Cannon (cannon dot danielc at gmail dot com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,18 +30,60 @@ if (!defined('MEDIAWIKI')) { } /** + * Unit to authenticate log-in attempts to the current wiki. + * * @addtogroup API */ class ApiLogin extends ApiBase { - + + /** + * Time (in seconds) a user must wait after submitting + * a bad login (will be multiplied by the THROTTLE_FACTOR for each bad attempt) + */ + const THROTTLE_TIME = 1; + + /** + * The factor by which the wait-time in between authentication + * attempts is increased every failed attempt. + */ + const THROTTLE_FACTOR = 2; + + /** + * The maximum number of failed logins after which the wait increase stops. + */ + const THOTTLE_MAX_COUNT = 10; + public function __construct($main, $action) { parent :: __construct($main, $action, 'lg'); } + /** + * Executes the log-in attempt using the parameters passed. If + * the log-in succeeeds, it attaches a cookie to the session + * and outputs the user id, username, and session token. If a + * log-in fails, as the result of a bad password, a nonexistant + * user, or any other reason, the host is cached with an expiry + * and no log-in attempts will be accepted until that expiry + * is reached. The expiry is $this->mLoginThrottle. + * + * @access public + */ public function execute() { $name = $password = $domain = null; extract($this->extractRequestParams()); + $result = array (); + + // Make sure noone is trying to guess the password brut-force + $nextLoginIn = $this->getNextLoginTimeout(); + if ($nextLoginIn > 0) { + $result['result'] = 'NeedToWait'; + $result['details'] = "Please wait $nextLoginIn seconds before next log-in attempt"; + $result['wait'] = $nextLoginIn; + $this->getResult()->addValue(null, 'login', $result); + return; + } + $params = new FauxRequest(array ( 'wpName' => $name, 'wpPassword' => $password, @@ -48,8 +91,6 @@ class ApiLogin extends ApiBase { 'wpRemember' => '' )); - $result = array (); - $loginForm = new LoginForm($params); switch ($loginForm->authenticateUserData()) { case LoginForm :: SUCCESS : @@ -86,9 +127,89 @@ class ApiLogin extends ApiBase { ApiBase :: dieDebug(__METHOD__, 'Unhandled case value'); } + if ($result['result'] != 'Success') { + $result['wait'] = $this->cacheBadLogin(); + } + // if we were allowed to try to login, memcache is fine + $this->getResult()->addValue(null, 'login', $result); } + + /** + * Caches a bad-login attempt associated with the host and with an + * expiry of $this->mLoginThrottle. These are cached by a key + * separate from that used by the captcha system--as such, logging + * in through the standard interface will get you a legal session + * and cookies to prove it, but will not remove this entry. + * + * Returns the number of seconds until next login attempt will be allowed. + * + * @access private + */ + private function cacheBadLogin() { + global $wgMemc; + + $key = $this->getMemCacheKey(); + $val = $wgMemc->get( $key ); + + $val['lastReqTime'] = time(); + if (!isset($val['count'])) { + $val['count'] = 1; + } else { + $val['count'] = 1 + $val['count']; + } + + $delay = ApiLogin::calculateDelay($val['count']); + + $wgMemc->delete($key); + // Cache expiration should be the maximum timeout - to prevent a "try and wait" attack + $wgMemc->add( $key, $val, ApiLogin::calculateDelay(ApiLogin::THOTTLE_MAX_COUNT) ); + + return $delay; + } + + /** + * How much time the client must wait before it will be + * allowed to try to log-in next. + * The return value is 0 if no wait is required. + */ + private function getNextLoginTimeout() { + global $wgMemc; + + $val = $wgMemc->get($this->getMemCacheKey()); + + $elapse = (time() - $val['lastReqTime']); // in seconds + $canRetryIn = ApiLogin::calculateDelay($val['count']) - $elapse; + + return $canRetryIn < 0 ? 0 : $canRetryIn; + } + + /** + * Based on the number of previously attempted logins, returns + * the delay (in seconds) when the next login attempt will be allowed. + */ + private static function calculateDelay($count) { + // Defensive programming + $count = intval($count); + $count = $count < 1 ? 1 : $count; + $count = $count > self::THOTTLE_MAX_COUNT ? self::THOTTLE_MAX_COUNT : $count; + + return self::THROTTLE_TIME + self::THROTTLE_TIME * ($count - 1) * self::THROTTLE_FACTOR; + } + + /** + * Internal cache key for badlogin checks. Robbed from the + * ConfirmEdit extension and modified to use a key unique to the + * API login.3 + * + * @return string + * @access private + */ + private function getMemCacheKey() { + return wfMemcKey( 'apilogin', 'badlogin', 'ip', wfGetIP() ); + } + protected function getAllowedParams() { return array ( 'name' => null, @@ -107,7 +228,11 @@ class ApiLogin extends ApiBase { protected function getDescription() { return array ( - 'This module is used to login and get the authentication tokens.' + 'This module is used to login and get the authentication tokens. ', + 'In the event of a successful log-in, a cookie will be attached', + 'to your session. In the event of a failed log-in, you will not ', + 'be able to attempt another log-in through this method for 60 seconds.', + 'This is to prevent password guessing by automated password crackers.' ); } @@ -118,7 +243,7 @@ class ApiLogin extends ApiBase { } public function getVersion() { - return __CLASS__ . ': $Id: ApiLogin.php 21402 2007-04-20 08:55:14Z nickj $'; + return __CLASS__ . ': $Id: ApiLogin.php 24695 2007-08-09 09:53:05Z yurik $'; } } -?> + -- cgit v1.2.3-54-g00ecf