aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/sessions.php
diff options
context:
space:
mode:
authormarcus <marcus@36083f99-b078-4883-b0ff-0f9b5a30f544>2009-01-14 15:10:39 +0000
committermarcus <marcus@36083f99-b078-4883-b0ff-0f9b5a30f544>2009-01-14 15:10:39 +0000
commitf4d6c6567fb9c23a9654e704045f03dbf10e467e (patch)
tree159581f9d394008fdab542237c3650a0b5b5967d /engine/lib/sessions.php
parentf2ac90d450c5b6888bf6323466b2dc9c3275f4bd (diff)
downloadelgg-f4d6c6567fb9c23a9654e704045f03dbf10e467e.tar.gz
elgg-f4d6c6567fb9c23a9654e704045f03dbf10e467e.tar.bz2
Closes #669: Logins rate limited. Accounts are limited to 5 fails in a 5 minute period, meaning an attacker can try one password per minute.
git-svn-id: https://code.elgg.org/elgg/trunk@2568 36083f99-b078-4883-b0ff-0f9b5a30f544
Diffstat (limited to 'engine/lib/sessions.php')
-rw-r--r--engine/lib/sessions.php76
1 files changed, 74 insertions, 2 deletions
diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php
index f3d828ca4..9336f0059 100644
--- a/engine/lib/sessions.php
+++ b/engine/lib/sessions.php
@@ -181,23 +181,93 @@
*/
function pam_auth_userpass($credentials = NULL)
{
+ $max_in_period = 3; // max 3 login attempts in
+ $period_length = 5; // 5 minutes
+ $periods = array();
+
if (is_array($credentials) && ($credentials['username']) && ($credentials['password']))
{
//$dbpassword = md5($credentials['password']);
if ($user = get_user_by_username($credentials['username'])) {
+
// Let admins log in without validating their email, but normal users must have validated their email
if ((!$user->admin) && (!$user->validated) && (!$user->admin_created) && (!$user->isBanned()))
return false;
- if ($user->password == generate_user_password($user, $credentials['password'])) {
+ if ($user->password == generate_user_password($user, $credentials['password']))
+
return true;
- }
+ else
+ // Password failed, log.
+ log_login_failure($user->guid);
+
}
}
return false;
+ }
+
+ function log_login_failure($user_guid)
+ {
+ $user_guid = (int)$user_guid;
+ $user = get_entity($user_guid);
+
+ if (($user_guid) && ($user) && ($user instanceof ElggUser))
+ {
+ $fails = (int)$user->getPrivateSetting("login_failures");
+ $fails++;
+
+ $user->setPrivateSetting("login_failures", $fails);
+ $user->setPrivateSetting("login_failure_$fails", time());
+ }
+ }
+
+ function reset_login_failure_count($user_guid)
+ {
+ $user_guid = (int)$user_guid;
+ $user = get_entity($user_guid);
+
+ if (($user_guid) && ($user) && ($user instanceof ElggUser))
+ {
+ $fails = (int)$user->getPrivateSetting("login_failures");
+
+ if ($fails) {
+ for ($n=1; $n <= $fails; $n++)
+ $user->removePrivateSetting("login_failure_$n");
+
+ $user->removePrivateSetting("login_failures");
+ }
+ }
+ }
+
+ function check_rate_limit_exceeded($user_guid)
+ {
+ $limit = 5;
+ $user_guid = (int)$user_guid;
+ $user = get_entity($user_guid);
+
+ if (($user_guid) && ($user) && ($user instanceof ElggUser))
+ {
+ $fails = (int)$user->getPrivateSetting("login_failures");
+ if ($fails >= $limit)
+ {
+ $cnt = 0;
+ $time = time();
+ for ($n=$fails; $n>0; $n--)
+ {
+ $f = $user->getPrivateSetting("login_failure_$n");
+ if ($f > $time - (60*5))
+ $cnt++;
+
+ if ($cnt==$limit) return true; // Limit reached
+ }
+ }
+
+ }
+
+ return false;
}
/**
@@ -214,6 +284,7 @@
global $CONFIG;
if ($user->isBanned()) return false; // User is banned, return false.
+ if (check_rate_limit_exceeded($user->guid)) return false; // Check rate limit
$_SESSION['user'] = $user;
$_SESSION['guid'] = $user->getGUID();
@@ -246,6 +317,7 @@
// Update statistics
set_last_login($_SESSION['guid']);
+ reset_login_failure_count($user->guid); // Reset any previous failed login attempts
return true;