diff --git a/Tests/routeTest.php b/Tests/routeTest.php index 4726757..7fed846 100644 --- a/Tests/routeTest.php +++ b/Tests/routeTest.php @@ -320,4 +320,22 @@ class test_route extends PHPUnit_Framework_TestCase echo $route->requestURL (); $this->expectOutputString("var=1"); } + + /** Ratelimiting in errors */ + public function test_errorRateLimit1 () + { + $route = new route (); + $route->error (new \Exception ("test1", 500)); + $route->error (new \Exception ("test2", 500)); + $route->error (new \Exception ("test3", 500)); + $route->error (new \Exception ("test4", 500)); + $route->error (new \Exception ("test5", 500)); + $route->error (new \Exception ("test6", 500)); + $route->error (new \Exception ("test7", 500)); + $route->error (new \Exception ("test8", 500)); + $route->error (new \Exception ("test9", 500)); + $route->error (new \Exception ("test0", 500)); + $route->error (new \Exception ("test11", 500)); + $this->expectOutputRegex("#Too much error requests#"); + } } diff --git a/route.php b/route.php index dda7c7c..e85163b 100644 --- a/route.php +++ b/route.php @@ -4,6 +4,7 @@ @author Dominique Fournier */ require_once ("domframework/http.php"); +require_once ("domframework/ratelimitfile.php"); /** The routing module, base of the DomFramework */ class route @@ -32,6 +33,9 @@ class route just display a "Unauthorized" message */ public $authenticationURL = null; + // Ratelimit the errors in route.php to not allow the hackers to brute force + // the backend. The objct can be put to null to disable the feature + public $ratelimiter = null; /// RENDERER PART /// /** Output type to no previous catched renderer (allow : json, xml, txt html) @@ -49,7 +53,13 @@ class route public $replacement = array(); /** Array to variable definition */ public $variable = array (); - + + /** The route constructor : initialize the parameters */ + function __construct () + { + $this->ratelimiter = new ratelimitfile (); + } + /** Return the baseURL of the site Always finish with a slash @param string|null $module The module name (if thereis one) */ @@ -486,14 +496,30 @@ class route @param $e Exception to print */ public function error ($e) { - if ($e->getCode () === "" || $e->getCode () === 0) - $getCode = 500; + $ipClient = null; + if (isset ($_SERVER["HTTP_X_FORWARDED_FOR"])) + $ipClient = $_SERVER["HTTP_X_FORWARDED_FOR"]; + elseif (isset ($_SERVER["REMOTE_ADDR"])) + $ipClient = $_SERVER["REMOTE_ADDR"]; + elseif (defined ("PHPUNIT")) + $ipClient = "CLI"; + if ($this->ratelimiter !== null && $ipClient !== null && + $this->ratelimiter->set ("error-$ipClient") === false) + { + $getCode = 406; + $message = dgettext("domframework", "Too much error requests"); + } else - $getCode = $e->getCode (); + { + if ($e->getCode () === "" || $e->getCode () === 0) + $getCode = 500; + else + $getCode = $e->getCode (); - $message = $e->getMessage (); - if ($e->getCode () === 0) - $message .= "

The Exception code was 0 and converted to 500

\n"; + $message = $e->getMessage (); + if ($e->getCode () === 0) + $message .= "

The Exception code was 0 and converted to 500

\n"; + } // If an error class/method is defined, use it in place of the default // one. @@ -508,7 +534,7 @@ class route $a = new $this->errors[0]; $method = $this->errors[1]; $a->$method ($getCode, $message); - exit; + return true; } if ($this->authenticationURL !== null && $getCode === 401) @@ -543,11 +569,11 @@ class route "{baseurlmodule}"=>$this->baseURLmodule())); $renderer->variable = $this->variable; $renderer->run (); - exit; + return true; $class = "output".$this->output; require_once ("$class.php"); $output = new $class (); $output->out ($message, $http->codetext ($getCode)); - exit; + return true; } }