mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-30 09:14:08 +02:00
parent
fe63ce664f
commit
e7da9c0a00
@ -8,10 +8,9 @@ use LogicException;
|
|||||||
use Zend_Form;
|
use Zend_Form;
|
||||||
use Zend_View_Interface;
|
use Zend_View_Interface;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Web\Session;
|
|
||||||
use Icinga\Web\Form\Decorator\HelpText;
|
use Icinga\Web\Form\Decorator\HelpText;
|
||||||
use Icinga\Web\Form\Decorator\ElementWrapper;
|
use Icinga\Web\Form\Decorator\ElementWrapper;
|
||||||
use Icinga\Web\Form\InvalidCSRFTokenException;
|
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for forms providing CSRF protection, confirmation logic and auto submission
|
* Base class for forms providing CSRF protection, confirmation logic and auto submission
|
||||||
@ -139,7 +138,7 @@ class Form extends Zend_Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->addElements($this->createElements($formData));
|
$this->addElements($this->createElements($formData));
|
||||||
$this->addCsrfToken()->addSubmitButton();
|
$this->addCsrfCounterMeasure()->addSubmitButton();
|
||||||
$this->created = true;
|
$this->created = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,17 +208,12 @@ class Form extends Zend_Form
|
|||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function addCsrfToken()
|
public function addCsrfCounterMeasure()
|
||||||
{
|
{
|
||||||
if (false === $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
|
if (false === $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
|
||||||
$this->addElement(
|
$element = new CsrfCounterMeasure($this->tokenElementName);
|
||||||
'hidden',
|
$element->setDecorators(array('ViewHelper'));
|
||||||
$this->tokenElementName,
|
$this->addElement($element);
|
||||||
array(
|
|
||||||
'ignore' => true,
|
|
||||||
'value' => $this->generateCsrfToken()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -293,7 +287,6 @@ class Form extends Zend_Form
|
|||||||
public function isValid($formData)
|
public function isValid($formData)
|
||||||
{
|
{
|
||||||
if ($this->isComplete($formData)) {
|
if ($this->isComplete($formData)) {
|
||||||
$this->assertValidCsrfToken($formData);
|
|
||||||
return parent::isValid($formData);
|
return parent::isValid($formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,56 +345,4 @@ class Form extends Zend_Form
|
|||||||
$this->create();
|
$this->create();
|
||||||
return parent::render($view);
|
return parent::render($view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a new (seed, token) pair
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function generateCsrfToken()
|
|
||||||
{
|
|
||||||
$seed = mt_rand();
|
|
||||||
$hash = hash('sha256', Session::getSession()->getId() . $seed);
|
|
||||||
return sprintf('%s|%s', $seed, $hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the submitted data for a correct CSRF token
|
|
||||||
*
|
|
||||||
* @param array $requestData The data sent by the user
|
|
||||||
*
|
|
||||||
* @throws InvalidCSRFTokenException When CSRF Validation fails
|
|
||||||
*/
|
|
||||||
protected function assertValidCsrfToken(array $requestData)
|
|
||||||
{
|
|
||||||
if (false === $this->tokenDisabled) {
|
|
||||||
if (false === isset($requestData[$this->tokenElementName])
|
|
||||||
|| false === $this->isValidCsrfToken($requestData[$this->tokenElementName])
|
|
||||||
) {
|
|
||||||
throw new InvalidCSRFTokenException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the given value is a valid CSRF token for the current session
|
|
||||||
*
|
|
||||||
* @param string $token Value from the CSRF form element
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isValidCsrfToken($token)
|
|
||||||
{
|
|
||||||
if (strpos($token, '|') === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
list($seed, $hash) = explode('|', $token);
|
|
||||||
|
|
||||||
if (false === is_numeric($seed)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hash === hash('sha256', Session::getSession()->getId() . $seed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
87
library/Icinga/Web/Form/Element/CsrfCounterMeasure.php
Normal file
87
library/Icinga/Web/Form/Element/CsrfCounterMeasure.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
|
namespace Icinga\Web\Form\Element;
|
||||||
|
|
||||||
|
use Zend_Form_Element_Xhtml;
|
||||||
|
use Icinga\Web\Session;
|
||||||
|
use Icinga\Web\Form\InvalidCSRFTokenException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSRF counter measure element
|
||||||
|
*
|
||||||
|
* You must not set a value to successfully use this element, just give it a name and you're good to go.
|
||||||
|
*/
|
||||||
|
class CsrfCounterMeasure extends Zend_Form_Element_Xhtml
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default form view helper to use for rendering
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $helper = 'formHidden';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this form element
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setRequired(true); // Not requiring this element would not make any sense
|
||||||
|
$this->setIgnore(true); // We do not want this element's value being retrieved by Form::getValues()
|
||||||
|
$this->setValue($this->generateCsrfToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether $value is a valid CSRF token
|
||||||
|
*
|
||||||
|
* @param string $value The value to check
|
||||||
|
* @param mixed $context Context to use
|
||||||
|
*
|
||||||
|
* @return bool True, in case the CSRF token is valid
|
||||||
|
*
|
||||||
|
* @throws InvalidCSRFTokenException In case the CSRF token is not valid
|
||||||
|
*/
|
||||||
|
public function isValid($value, $context = null)
|
||||||
|
{
|
||||||
|
if (parent::isValid($value, $context) && $this->isValidCsrfToken($value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidCSRFTokenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given value is a valid CSRF token for the current session
|
||||||
|
*
|
||||||
|
* @param string $token The CSRF token
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isValidCsrfToken($token)
|
||||||
|
{
|
||||||
|
if (strpos($token, '|') === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($seed, $hash) = explode('|', $token);
|
||||||
|
|
||||||
|
if (false === is_numeric($seed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hash === hash('sha256', Session::getSession()->getId() . $seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a new (seed, token) pair
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function generateCsrfToken()
|
||||||
|
{
|
||||||
|
$seed = mt_rand();
|
||||||
|
$hash = hash('sha256', Session::getSession()->getId() . $seed);
|
||||||
|
return sprintf('%s|%s', $seed, $hash);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user