From 978f15357cb563233fddfc9c02128bf62f419ef9 Mon Sep 17 00:00:00 2001 From: lovenunu Date: Mon, 14 Jul 2014 20:58:44 +0200 Subject: [PATCH] Apply firewall security on BaseForm::validateForm modified: core/lib/Thelia/Controller/BaseController.php modified: core/lib/Thelia/Form/AddressCreateForm.php new file: core/lib/Thelia/Form/FirewallForm.php modified: core/lib/Thelia/Model/FormFirewall.php modified: setup/insert.sql --- core/lib/Thelia/Controller/BaseController.php | 9 ++ core/lib/Thelia/Form/AddressCreateForm.php | 2 +- core/lib/Thelia/Form/FirewallForm.php | 96 +++++++++++++++++++ core/lib/Thelia/Model/FormFirewall.php | 16 ++++ setup/insert.sql | 5 +- 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 core/lib/Thelia/Form/FirewallForm.php diff --git a/core/lib/Thelia/Controller/BaseController.php b/core/lib/Thelia/Controller/BaseController.php index 41fa50067..d396fc8ca 100644 --- a/core/lib/Thelia/Controller/BaseController.php +++ b/core/lib/Thelia/Controller/BaseController.php @@ -25,6 +25,7 @@ use Symfony\Component\Routing\Router; use Thelia\Core\Template\TemplateHelper; use Thelia\Core\Translation\Translator; +use Thelia\Form\FirewallForm; use Thelia\Model\OrderQuery; use Thelia\Tools\Redirect; @@ -200,6 +201,14 @@ abstract class BaseController extends ContainerAware $form->bind($aBaseForm->getRequest()); if ($form->isValid()) { + if ($aBaseForm instanceof FirewallForm && !$aBaseForm->isFirewallOk()) { + throw new FormValidationException( + $this->getTranslator()->trans( + "You have too much sent this form. Please wait before trying again." + ) + ); + } + return $form; } else { $errorMessage = null; diff --git a/core/lib/Thelia/Form/AddressCreateForm.php b/core/lib/Thelia/Form/AddressCreateForm.php index 289d809dd..b88ed341d 100644 --- a/core/lib/Thelia/Form/AddressCreateForm.php +++ b/core/lib/Thelia/Form/AddressCreateForm.php @@ -21,7 +21,7 @@ use Thelia\Core\Translation\Translator; * @package Thelia\Form * @author Manuel Raynaud */ -class AddressCreateForm extends BaseForm +class AddressCreateForm extends FirewallForm { /** diff --git a/core/lib/Thelia/Form/FirewallForm.php b/core/lib/Thelia/Form/FirewallForm.php new file mode 100644 index 000000000..e39e45f92 --- /dev/null +++ b/core/lib/Thelia/Form/FirewallForm.php @@ -0,0 +1,96 @@ + + */ +abstract class FirewallForm extends BaseForm +{ + /** @var \Thelia\Model\FormFirewall */ + protected static $cachedInstance; + + public function __construct(Request $request, $type = "form", $data = array(), $options = array()) + { + parent::__construct($request, $type, $data, $options); + + static::$cachedInstance = FormFirewallQuery::create() + ->filterByFormName($this->getName()) + ->filterByIpAddress($this->request->getClientIp()) + ->findOne() + ; + } + + public function isFirewallOk() + { + if (null !== $firewallRow = &static::$cachedInstance) { + /** @var \DateTime $lastRequestDateTime */ + $lastRequestDateTime = $firewallRow->getUpdatedAt(); + + $lastRequestTimestamp = $lastRequestDateTime->getTimestamp(); + + /** + * Get the last request execution time in hour. + */ + $lastRequest = (time() - $lastRequestTimestamp) / 3600; + + if ($lastRequest > $this->getConfigTime()) { + $firewallRow->resetAttempts(); + } + + if ($firewallRow->getAttempts() <= $this->getConfigAttempts()) { + $firewallRow->incrementAttempts(); + } else { + /** Set updated_at at NOW() */ + $firewallRow->save(); + + return false; + } + } else { + $firewallRow = (new FormFirewall()) + ->setIpAddress($this->request->getClientIp()) + ->setFormName($this->getName()) + ; + $firewallRow->save(); + + static::$cachedInstance = $firewallRow; + } + + return true; + } + + /** + * @return int + * + * The time (in hours) to wait if the attempts have been exceeded + */ + public function getConfigTime() + { + return ConfigQuery::read("form_firewall_time_to_wait", 1); + } + + /** + * @return int + * + * The number of allowed attempts + */ + public function getConfigAttempts() + { + return ConfigQuery::read("form_firewall_attempts", 2); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/FormFirewall.php b/core/lib/Thelia/Model/FormFirewall.php index cb20d8118..0f50e62d1 100644 --- a/core/lib/Thelia/Model/FormFirewall.php +++ b/core/lib/Thelia/Model/FormFirewall.php @@ -6,5 +6,21 @@ use Thelia\Model\Base\FormFirewall as BaseFormFirewall; class FormFirewall extends BaseFormFirewall { + public function resetAttempts() + { + $this->setAttempts(1)->save(); + return $this; + } + + public function incrementAttempts() + { + $this->setAttempts( + $this->getAttempts() + 1 + ); + + $this->save(); + + return $this; + } } diff --git a/setup/insert.sql b/setup/insert.sql index a3ad537b1..69a1ab64b 100644 --- a/setup/insert.sql +++ b/setup/insert.sql @@ -51,7 +51,10 @@ INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updat ('front_cart_country_cookie_name','fcccn', 1, 1, NOW(), NOW()), ('front_cart_country_cookie_expires','2592000', 1, 1, NOW(), NOW()), ('sitemap_ttl','7200', 1, 1, NOW(), NOW()), -('feed_ttl','7200', 1, 1, NOW(), NOW()); +('feed_ttl','7200', 1, 1, NOW(), NOW()), + +('form_firewall_time_to_wait', '1', 1, 1, NOW(), NOW()), +('form_firewall_attempts', '3', 1, 1, NOW(), NOW()); INSERT INTO `config_i18n` (`id`, `locale`, `title`, `description`, `chapo`, `postscriptum`) VALUES