2014-08-12 14:43:10 +02:00
|
|
|
<?php
|
|
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
|
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
|
|
|
|
|
|
|
namespace Icinga\Web\Form\Element;
|
|
|
|
|
|
|
|
use Icinga\Web\Session;
|
2014-10-06 10:19:36 +02:00
|
|
|
use Icinga\Web\Form\FormElement;
|
2014-08-12 14:43:10 +02:00
|
|
|
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.
|
|
|
|
*/
|
2014-10-06 10:19:36 +02:00
|
|
|
class CsrfCounterMeasure extends FormElement
|
2014-08-12 14:43:10 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Default form view helper to use for rendering
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
public $helper = 'formHidden';
|
|
|
|
|
2014-10-06 10:19:36 +02:00
|
|
|
/**
|
|
|
|
* Counter measure element is required
|
|
|
|
*
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $_ignore = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ignore element when retrieving values at form level
|
|
|
|
*
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $_required = true;
|
|
|
|
|
2014-08-12 14:43:10 +02:00
|
|
|
/**
|
|
|
|
* Initialize this form element
|
|
|
|
*/
|
|
|
|
public function init()
|
|
|
|
{
|
2014-10-06 10:19:36 +02:00
|
|
|
$this->addDecorator('ViewHelper');
|
2014-08-12 14:43:10 +02:00
|
|
|
$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);
|
|
|
|
}
|
|
|
|
}
|