diff options
author | Bharat Mediratta <bharat@menalto.com> | 2010-01-30 19:48:57 -0800 |
---|---|---|
committer | Bharat Mediratta <bharat@menalto.com> | 2010-01-30 19:48:57 -0800 |
commit | 2bfcec9620814a6f3d0163a174d7ba90efef369d (patch) | |
tree | aff296f37e108af420058e029fe107d0cde0bbb0 | |
parent | 86fd81ef2661718914e1d4eb63108a864b6ac14c (diff) |
Prevent brute force login attacks by reducing login attempts to 1 per
minute after there have been 5 consecutive failed login attempts.
Fix for ticket #589.
-rw-r--r-- | modules/gallery/controllers/login.php | 7 | ||||
-rw-r--r-- | modules/gallery/helpers/auth.php | 45 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_event.php | 5 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_installer.php | 22 | ||||
-rw-r--r-- | modules/gallery/models/failed_login.php | 20 | ||||
-rw-r--r-- | modules/gallery/module.info | 3 |
6 files changed, 94 insertions, 8 deletions
diff --git a/modules/gallery/controllers/login.php b/modules/gallery/controllers/login.php index cfe86cfb..1426f0d8 100644 --- a/modules/gallery/controllers/login.php +++ b/modules/gallery/controllers/login.php @@ -62,11 +62,10 @@ class Login_Controller extends Controller { if ($valid) { $user = identity::lookup_user_by_name($form->login->inputs["name"]->value); if (empty($user) || !identity::is_correct_password($user, $form->login->password->value)) { - log::warning( - "user", - t("Failed login for %name", - array("name" => $form->login->inputs["name"]->value))); $form->login->inputs["name"]->add_error("invalid_login", 1); + $name = $form->login->inputs["name"]->value; + log::warning("user", t("Failed login for %name", array("name" => $name))); + module::event("user_login_failed", $name); $valid = false; } } diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index f7d4f7e8..e112f127 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -22,7 +22,10 @@ class auth_Core { $form = new Forge($url, "", "post", array("id" => "g-login-form")); $form->set_attr('class', "g-narrow"); $group = $form->group("login")->label(t("Login")); - $group->input("name")->label(t("Username"))->id("g-username")->class(null); + $group->input("name")->label(t("Username"))->id("g-username")->class(null) + ->callback("auth::validate_too_many_failed_logins") + ->error_messages( + "too_many_failed_logins", t("Too many failed login attempts. Try again later")); $group->password("password")->label(t("Password"))->id("g-password")->class(null); $group->inputs["name"]->error_messages("invalid_login", t("Invalid name or password")); $group->submit("")->value(t("Login")); @@ -55,4 +58,44 @@ class auth_Core { array("url" => user_profile::url($user->id), "user_name" => html::clean($user->name)))); } + + /** + * After there have been 5 failed login attempts, any failure leads to getting locked out for a + * minute. + */ + static function validate_too_many_failed_logins($name_input) { + $failed_login = ORM::factory("failed_login") + ->where("name", "=", $name_input->value) + ->find(); + if ($failed_login->loaded() && + $failed_login->count > 5 && + (time() - $failed_login->time < 60)) { + $name_input->add_error("too_many_failed_logins", 1); + } + } + + /** + * Record a failed login for this user + */ + static function record_failed_login($name) { + $failed_login = ORM::factory("failed_login") + ->where("name", "=", $name) + ->find(); + if (!$failed_login->loaded()) { + $failed_login->name = $name; + } + $failed_login->time = time(); + $failed_login->count++; + $failed_login->save(); + } + + /** + * Clear any failed logins for this user + */ + static function record_successful_login($user) { + db::build() + ->delete("failed_logins") + ->where("name", "=", $user->name) + ->execute(); + } }
\ No newline at end of file diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 80452276..6479e2c3 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -110,6 +110,11 @@ class gallery_event_Core { graphics::choose_default_toolkit(); module::clear_var("gallery", "choose_default_tookit"); } + auth::record_successful_login($user); + } + + static function user_login_failed($name) { + auth::record_failed_login($name); } static function item_index_data($item, $data) { diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index d2378d64..cf701ed4 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -42,6 +42,14 @@ class gallery_installer { KEY (`tags`)) DEFAULT CHARSET=utf8;"); + $db->query("CREATE TABLE {failed_logins} ( + `id` int(9) NOT NULL auto_increment, + `count` int(9) NOT NULL, + `name` varchar(255) NOT NULL, + `time` int(9) NOT NULL, + PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8;"); + $db->query("CREATE TABLE {graphics_rules} ( `id` int(9) NOT NULL auto_increment, `active` BOOLEAN default 0, @@ -276,7 +284,7 @@ class gallery_installer { // @todo this string needs to be picked up by l10n_scanner module::set_var("gallery", "credits", "Powered by <a href=\"%url\">Gallery %version</a>"); module::set_var("gallery", "simultaneous_upload_limit", 5); - module::set_version("gallery", 22); + module::set_version("gallery", 23); } static function upgrade($version) { @@ -485,6 +493,17 @@ class gallery_installer { } module::set_version("gallery", $version = 23); } + + if ($version = 23) { + $db->query("CREATE TABLE {failed_logins} ( + `id` int(9) NOT NULL auto_increment, + `count` int(9) NOT NULL, + `name` varchar(255) NOT NULL, + `time` int(9) NOT NULL, + PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8;"); + module::set_version("gallery", $version = 24); + } } static function uninstall() { @@ -493,6 +512,7 @@ class gallery_installer { $db->query("DROP TABLE IF EXISTS {access_intents}"); $db->query("DROP TABLE IF EXISTS {graphics_rules}"); $db->query("DROP TABLE IF EXISTS {incoming_translations}"); + $db->query("DROP TABLE IF EXISTS {failed_logins}"); $db->query("DROP TABLE IF EXISTS {items}"); $db->query("DROP TABLE IF EXISTS {logs}"); $db->query("DROP TABLE IF EXISTS {modules}"); diff --git a/modules/gallery/models/failed_login.php b/modules/gallery/models/failed_login.php new file mode 100644 index 00000000..0b84c295 --- /dev/null +++ b/modules/gallery/models/failed_login.php @@ -0,0 +1,20 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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 + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Failed_Login_Model extends ORM {} diff --git a/modules/gallery/module.info b/modules/gallery/module.info index ee169cf1..5d0dd3c5 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,4 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 23 - +version = 24 |