pachoofoosh
08-06-2013, 03:55 PM
A simple way to help stop brute-force attacks, taking advantage of PHP's sleep() function.
This mod automatically records login attempts to the database. If an IP has 5 or more login attempts, the script will start delaying for them, slowing the attack to a crawl. On successful login, all of the IP's login attempts are cleared.
How to 'install'
Step 1.) Open up classes/class_sidebar.php. Replace its contents with the following:
<?php
/**
* The Sidebar Class, defines a standard HTML Sidebar component.
* It extends from the Widget class, while adding its own implementation.
* @category Resource
* @package Widget
* @author Hall of Famer
* @copyright Mysidia Adoptables Script
* @link http://www.mysidiaadoptables.com
* @since 1.3.3
* @todo Not much at this point.
*
*/
class Sidebar extends Widget{
/**
* The moneyBar property, specifies the money/donation bar for members.
* @access protected
* @var Paragraph
*/
protected $moneyBar;
/**
* The linksBar property, stores all useful links for members.
* @access protected
* @var Paragraph
*/
protected $linksBar;
/**
* The wolBar property, determines the who's online url in the sidebar.
* @access protected
* @var Link
*/
protected $wolBar;
/**
* The loginBar property, specifies the loginBar for guests.
* @access protected
* @var FormBuilder
*/
protected $loginBar;
/**
* Constructor of Sidebar Class, it initializes basic sidebar properties
* @access public
* @return Void
*/
public function __construct(){
$mysidia = Registry::get("mysidia");
$userLevel = ($mysidia->user->isloggedin)?"member":"visitor";
$stmt = $mysidia->db->select("modules", array(), "widget = 'sidebar' and (userlevel = '{$userLevel}' or userlevel = 'user') and status = 'enabled' ORDER BY `order`");
while($module = $stmt->fetchObject()){
$method = "set{$module->name}";
if($this->hasMethod($method)) $this->$method();
else $this->setModule($module);
}
}
/**
* The setDivision method, setter method for property $division.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @param GUIComponent $module
* @access protected
* @return Void
*/
protected function setDivision(GUIComponent $module){
if(!$this->division){
$this->division = new Division;
$this->division->setClass("sidebar");
}
$this->division->add($module);
}
/**
* The getMoneyBar method, getter method for property $moneyBar.
* @access public
* @return Paragraph
*/
public function getMoneyBar(){
return $this->moneyBar;
}
/**
* The setMoneyBar method, setter method for property $moneyBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setMoneyBar(){
$mysidia = Registry::get("mysidia");
$this->moneyBar = new Paragraph;
$this->moneyBar->add(new Comment("You have {$mysidia->user->money} {$mysidia->user->cost}."));
$donate = new Link("donate");
$donate->setText("Donate Money to Friends");
$this->moneyBar->add($donate);
$this->setDivision($this->moneyBar);
}
/**
* The getLinksBar method, getter method for property $linksBar.
* @access public
* @return Paragraph
*/
public function getLinksBar(){
return $this->linksBar;
}
/**
* The setLinksBar method, setter method for property $linksBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLinksBar(){
$mysidia = Registry::get("mysidia");
$this->linksBar = new Paragraph;
$linkTitle = new Comment("My Links:");
$linkTitle->setBold();
$this->linksBar->add($linkTitle);
$linksList = new LinksList("ul");
$this->setLinks($linksList);
$this->linksBar->add($linksList);
$this->setDivision($this->linksBar);
}
/**
* The setLinks method, append all links to the LinksBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLinks(LinksList $linksList){
$mysidia = Registry::get("mysidia");
$stmt = $mysidia->db->select("links", array("id", "linktext", "linkurl"), "linktype = 'sidelink' ORDER BY linkorder");
if($stmt->rowCount() == 0) Throw new Exception("There is an error with sidebar links, please contact the admin immediately for help.");
while($sideLink = $stmt->fetchObject()){
$link = new Link($sideLink->linkurl);
$link->setText($sideLink->linktext);
if($sideLink->linkurl == "messages"){
$num = $mysidia->db->select("messages", array("touser"), "touser='{$mysidia->user->username}' and status='unread'")->rowCount();
if($num > 0) $link->setText("{$link->getText()} ({$num})");
}
$link->setListed(TRUE);
$linksList->add($link);
}
if($mysidia->user instanceof Admin){
$adminCP = new Link("admincp/", FALSE, FALSE);
$adminCP->setText("Admin Control Panel");
$adminCP->setListed(TRUE);
$linksList->add($adminCP);
}
}
/**
* The getWolBar method, getter method for property $wolBar.
* @access public
* @return LinksList
*/
public function getWolBar(){
return $this->wolBar;
}
/**
* The setWolBar method, setter method for property $wolBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setWolBar(){
$mysidia = Registry::get("mysidia");
$this->wolBar = new Link("online");
$online = $mysidia->db->select("online", array(), "username != 'Visitor'")->rowCount();
$offline = $mysidia->db->select("online", array(), "username = 'Visitor'")->rowCount();
$this->wolBar->setText("There are {$online} users and {$offline} guests online.");
$this->setDivision($this->wolBar);
}
/**
* The getLoginBar method, getter method for property $loginBar.
* @access public
* @return FormBuilder
*/
public function getLoginBar(){
return $this->loginBar;
}
/**
* The setLoginBar method, setter method for property $loginBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLoginBar(){
include ('/functions/functions.php');
$this->loginBar = new FormBuilder("login", "login", "post");
$loginTitle = new Comment("Member Login:");
$loginTitle->setBold();
$loginTitle->setUnderlined();
$this->loginBar->add($loginTitle);
$this->loginBar->buildComment("<label for='username'>username:</label><br /> ", FALSE)
->buildTextField("username")
->buildComment("<label for='password'>password:</label><br /> ", FALSE)
->buildPasswordField("password", "password", "", TRUE)
->buildButton("Log In", "submit", "submit")
->buildComment("Don't have an account?");
$register = new Link("register");
$register->setText("Register new Account");
$register->setLineBreak(TRUE);
$forgot = new Link("forgotpass");
$forgot->setText("Forgot password?");
$this->loginBar->add($register);
$this->loginBar->add($forgot);
$this->setDivision($this->loginBar);
}
public function setModule($module){
$mysidia = Registry::get("mysidia");
$moduleContainer = new Paragraph();
if($module->subtitle) $moduleContainer->add(new Comment($module->subtitle, TRUE, "b"));
if($module->php) eval($module->php);
if($module->html) $moduleContainer->add(new Comment($module->html));
$this->setDivision($moduleContainer);
}
/**
* The render method for Sidebar class, it renders the division component and thus all subcomponents.
* @access public
* @return String
*/
public function render(){
return $this->division->render();
}
}
?>
Step 2.) Open up functions/functions.php. Now let's create the anti brute-force function, logAttempt(). Paste the following into the bottom of the file, just above the ending PHP tag (?>):
function logAttempt() {
$mysidia = Registry::get("mysidia");
$ip = $_SERVER['REMOTE_ADDR'];
$query = $mysidia->db->select("login_attempts", array("num_attempts"), "ip = '$ip'")->rowCount();
$attempts = $query + 1;
$stmt = $mysidia->db->insert("login_attempts", array("num_attempts" => "$attempts", "ip" => "$ip"));
if( $attempts <= 4 ) { // Equal to or less than 4 login attempts..
$delay_time = 0;
}
elseif( $attempts == 5 ) { // Five login attempts...
$delay_time = 2;
}
elseif( $attempts >= 6 ) { // Greater than or equal to 6 login attempts...
$delay_time = 5;
}
return sleep($delay_time);
} // End logAttempt function.
Step 3.) We're almost finished; halfway there. c; Open up login.php. Replace its contents with the following:
<?php
class LoginController extends AppController{
private $view;
private $subController;
public function __construct(){
parent::__construct();
}
public function index(){
$this->flag = "guest";
$this->handleAccess();
$mysidia = Registry::get("mysidia");
$document = $mysidia->frame->getDocument();
if($mysidia->input->post("submit")){
if(!$mysidia->input->post("username") or !$mysidia->input->post("password")){
$document->setTitle($mysidia->lang->fail_title);
$document->addLangvar($mysidia->lang->fail_blank);
}
else{
$validator = new UserValidator($mysidia->user, array("username" => $mysidia->input->post("username"), "password" => $mysidia->input->post("password")));
$validator->validate("username");
$validator->validate("password");
if(!$validator->triggererror()){
// Validation succeeded, now begins the actual login procedure
$document->setTitle($mysidia->lang->success_title);
$document->addLangvar("Welcome back, {$mysidia->input->post("username")}! {$mysidia->lang->success}");
$ip = $_SERVER['REMOTE_ADDR']; // Delete the user's previous login attempts.
$mysidia->db->delete("login_attempts", "ip = '$ip'");
$mysidia->user->login($mysidia->input->post("username"));
if($mybbenabled == 1) $mysidia->user->loginforum();
$mysidia->session->terminate("clientip");
}
else{
$document->setTitle($mysidia->lang->fail_title);
$document->addLangvar($mysidia->lang->fail_details);
logAttempt();
$mysidia->cookies->logincookies();
}
}
return;
}
$mysidia->session->assign("clientip", $_SERVER['REMOTE_ADDR']);
$document->setTitle($mysidia->lang->title);
$document->addLangvar($mysidia->lang->login);
$loginForm = $mysidia->frame->getSidebar()->getLoginBar();
$document->add($loginForm);
}
public function logout(){
$this->flag = "member";
$this->handleAccess();
$mysidia = Registry::get("mysidia");
$document = $mysidia->frame->getDocument();
$mysidia->user->logout();
$document->setTitle($mysidia->lang->logout_title);
$document->addLangvar($mysidia->lang->logout);
}
}
?>
Step 4.) And finally, let's create the login_attempts table. uwu Open up PHPMyAdmin and click on the database you're going to use. Next, click the button that says '(+) New table' (At the bottom of the frame on the left side of the screen which displays all of the DB's tables).
For the criteria, it should look something like this:
http://i42.tinypic.com/8wh4qo.png
And with that, everything is finished! :D If you come across any errors while using this Mod, I'll be happy to help fix it. Hope you guys will find good use of it! c:
This mod automatically records login attempts to the database. If an IP has 5 or more login attempts, the script will start delaying for them, slowing the attack to a crawl. On successful login, all of the IP's login attempts are cleared.
How to 'install'
Step 1.) Open up classes/class_sidebar.php. Replace its contents with the following:
<?php
/**
* The Sidebar Class, defines a standard HTML Sidebar component.
* It extends from the Widget class, while adding its own implementation.
* @category Resource
* @package Widget
* @author Hall of Famer
* @copyright Mysidia Adoptables Script
* @link http://www.mysidiaadoptables.com
* @since 1.3.3
* @todo Not much at this point.
*
*/
class Sidebar extends Widget{
/**
* The moneyBar property, specifies the money/donation bar for members.
* @access protected
* @var Paragraph
*/
protected $moneyBar;
/**
* The linksBar property, stores all useful links for members.
* @access protected
* @var Paragraph
*/
protected $linksBar;
/**
* The wolBar property, determines the who's online url in the sidebar.
* @access protected
* @var Link
*/
protected $wolBar;
/**
* The loginBar property, specifies the loginBar for guests.
* @access protected
* @var FormBuilder
*/
protected $loginBar;
/**
* Constructor of Sidebar Class, it initializes basic sidebar properties
* @access public
* @return Void
*/
public function __construct(){
$mysidia = Registry::get("mysidia");
$userLevel = ($mysidia->user->isloggedin)?"member":"visitor";
$stmt = $mysidia->db->select("modules", array(), "widget = 'sidebar' and (userlevel = '{$userLevel}' or userlevel = 'user') and status = 'enabled' ORDER BY `order`");
while($module = $stmt->fetchObject()){
$method = "set{$module->name}";
if($this->hasMethod($method)) $this->$method();
else $this->setModule($module);
}
}
/**
* The setDivision method, setter method for property $division.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @param GUIComponent $module
* @access protected
* @return Void
*/
protected function setDivision(GUIComponent $module){
if(!$this->division){
$this->division = new Division;
$this->division->setClass("sidebar");
}
$this->division->add($module);
}
/**
* The getMoneyBar method, getter method for property $moneyBar.
* @access public
* @return Paragraph
*/
public function getMoneyBar(){
return $this->moneyBar;
}
/**
* The setMoneyBar method, setter method for property $moneyBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setMoneyBar(){
$mysidia = Registry::get("mysidia");
$this->moneyBar = new Paragraph;
$this->moneyBar->add(new Comment("You have {$mysidia->user->money} {$mysidia->user->cost}."));
$donate = new Link("donate");
$donate->setText("Donate Money to Friends");
$this->moneyBar->add($donate);
$this->setDivision($this->moneyBar);
}
/**
* The getLinksBar method, getter method for property $linksBar.
* @access public
* @return Paragraph
*/
public function getLinksBar(){
return $this->linksBar;
}
/**
* The setLinksBar method, setter method for property $linksBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLinksBar(){
$mysidia = Registry::get("mysidia");
$this->linksBar = new Paragraph;
$linkTitle = new Comment("My Links:");
$linkTitle->setBold();
$this->linksBar->add($linkTitle);
$linksList = new LinksList("ul");
$this->setLinks($linksList);
$this->linksBar->add($linksList);
$this->setDivision($this->linksBar);
}
/**
* The setLinks method, append all links to the LinksBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLinks(LinksList $linksList){
$mysidia = Registry::get("mysidia");
$stmt = $mysidia->db->select("links", array("id", "linktext", "linkurl"), "linktype = 'sidelink' ORDER BY linkorder");
if($stmt->rowCount() == 0) Throw new Exception("There is an error with sidebar links, please contact the admin immediately for help.");
while($sideLink = $stmt->fetchObject()){
$link = new Link($sideLink->linkurl);
$link->setText($sideLink->linktext);
if($sideLink->linkurl == "messages"){
$num = $mysidia->db->select("messages", array("touser"), "touser='{$mysidia->user->username}' and status='unread'")->rowCount();
if($num > 0) $link->setText("{$link->getText()} ({$num})");
}
$link->setListed(TRUE);
$linksList->add($link);
}
if($mysidia->user instanceof Admin){
$adminCP = new Link("admincp/", FALSE, FALSE);
$adminCP->setText("Admin Control Panel");
$adminCP->setListed(TRUE);
$linksList->add($adminCP);
}
}
/**
* The getWolBar method, getter method for property $wolBar.
* @access public
* @return LinksList
*/
public function getWolBar(){
return $this->wolBar;
}
/**
* The setWolBar method, setter method for property $wolBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setWolBar(){
$mysidia = Registry::get("mysidia");
$this->wolBar = new Link("online");
$online = $mysidia->db->select("online", array(), "username != 'Visitor'")->rowCount();
$offline = $mysidia->db->select("online", array(), "username = 'Visitor'")->rowCount();
$this->wolBar->setText("There are {$online} users and {$offline} guests online.");
$this->setDivision($this->wolBar);
}
/**
* The getLoginBar method, getter method for property $loginBar.
* @access public
* @return FormBuilder
*/
public function getLoginBar(){
return $this->loginBar;
}
/**
* The setLoginBar method, setter method for property $loginBar.
* It is set internally upon object instantiation, cannot be accessed in client code.
* @access protected
* @return Void
*/
protected function setLoginBar(){
include ('/functions/functions.php');
$this->loginBar = new FormBuilder("login", "login", "post");
$loginTitle = new Comment("Member Login:");
$loginTitle->setBold();
$loginTitle->setUnderlined();
$this->loginBar->add($loginTitle);
$this->loginBar->buildComment("<label for='username'>username:</label><br /> ", FALSE)
->buildTextField("username")
->buildComment("<label for='password'>password:</label><br /> ", FALSE)
->buildPasswordField("password", "password", "", TRUE)
->buildButton("Log In", "submit", "submit")
->buildComment("Don't have an account?");
$register = new Link("register");
$register->setText("Register new Account");
$register->setLineBreak(TRUE);
$forgot = new Link("forgotpass");
$forgot->setText("Forgot password?");
$this->loginBar->add($register);
$this->loginBar->add($forgot);
$this->setDivision($this->loginBar);
}
public function setModule($module){
$mysidia = Registry::get("mysidia");
$moduleContainer = new Paragraph();
if($module->subtitle) $moduleContainer->add(new Comment($module->subtitle, TRUE, "b"));
if($module->php) eval($module->php);
if($module->html) $moduleContainer->add(new Comment($module->html));
$this->setDivision($moduleContainer);
}
/**
* The render method for Sidebar class, it renders the division component and thus all subcomponents.
* @access public
* @return String
*/
public function render(){
return $this->division->render();
}
}
?>
Step 2.) Open up functions/functions.php. Now let's create the anti brute-force function, logAttempt(). Paste the following into the bottom of the file, just above the ending PHP tag (?>):
function logAttempt() {
$mysidia = Registry::get("mysidia");
$ip = $_SERVER['REMOTE_ADDR'];
$query = $mysidia->db->select("login_attempts", array("num_attempts"), "ip = '$ip'")->rowCount();
$attempts = $query + 1;
$stmt = $mysidia->db->insert("login_attempts", array("num_attempts" => "$attempts", "ip" => "$ip"));
if( $attempts <= 4 ) { // Equal to or less than 4 login attempts..
$delay_time = 0;
}
elseif( $attempts == 5 ) { // Five login attempts...
$delay_time = 2;
}
elseif( $attempts >= 6 ) { // Greater than or equal to 6 login attempts...
$delay_time = 5;
}
return sleep($delay_time);
} // End logAttempt function.
Step 3.) We're almost finished; halfway there. c; Open up login.php. Replace its contents with the following:
<?php
class LoginController extends AppController{
private $view;
private $subController;
public function __construct(){
parent::__construct();
}
public function index(){
$this->flag = "guest";
$this->handleAccess();
$mysidia = Registry::get("mysidia");
$document = $mysidia->frame->getDocument();
if($mysidia->input->post("submit")){
if(!$mysidia->input->post("username") or !$mysidia->input->post("password")){
$document->setTitle($mysidia->lang->fail_title);
$document->addLangvar($mysidia->lang->fail_blank);
}
else{
$validator = new UserValidator($mysidia->user, array("username" => $mysidia->input->post("username"), "password" => $mysidia->input->post("password")));
$validator->validate("username");
$validator->validate("password");
if(!$validator->triggererror()){
// Validation succeeded, now begins the actual login procedure
$document->setTitle($mysidia->lang->success_title);
$document->addLangvar("Welcome back, {$mysidia->input->post("username")}! {$mysidia->lang->success}");
$ip = $_SERVER['REMOTE_ADDR']; // Delete the user's previous login attempts.
$mysidia->db->delete("login_attempts", "ip = '$ip'");
$mysidia->user->login($mysidia->input->post("username"));
if($mybbenabled == 1) $mysidia->user->loginforum();
$mysidia->session->terminate("clientip");
}
else{
$document->setTitle($mysidia->lang->fail_title);
$document->addLangvar($mysidia->lang->fail_details);
logAttempt();
$mysidia->cookies->logincookies();
}
}
return;
}
$mysidia->session->assign("clientip", $_SERVER['REMOTE_ADDR']);
$document->setTitle($mysidia->lang->title);
$document->addLangvar($mysidia->lang->login);
$loginForm = $mysidia->frame->getSidebar()->getLoginBar();
$document->add($loginForm);
}
public function logout(){
$this->flag = "member";
$this->handleAccess();
$mysidia = Registry::get("mysidia");
$document = $mysidia->frame->getDocument();
$mysidia->user->logout();
$document->setTitle($mysidia->lang->logout_title);
$document->addLangvar($mysidia->lang->logout);
}
}
?>
Step 4.) And finally, let's create the login_attempts table. uwu Open up PHPMyAdmin and click on the database you're going to use. Next, click the button that says '(+) New table' (At the bottom of the frame on the left side of the screen which displays all of the DB's tables).
For the criteria, it should look something like this:
http://i42.tinypic.com/8wh4qo.png
And with that, everything is finished! :D If you come across any errors while using this Mod, I'll be happy to help fix it. Hope you guys will find good use of it! c: