Add CSRF support in form

Get the values provided by the user with a method with CSRF validation
Remove the verify support as it is not used (and it use eval function which is evil)


git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@1371 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
2014-06-01 06:03:52 +00:00
parent a2e0be173f
commit cba4fcc57c

115
form.php
View File

@@ -16,6 +16,15 @@ class form
private $formName;
/** Allow to debug the PHP */
public $debug=0;
/** CSRF protection
By default, the CSRF protection is active if a SESSION is active too.
It can be disabled if needed. An Exception is raised if the form is send
back without the token */
public $csrf=TRUE;
public $csrfField = "CSRF_TOKEN";
/** The method used to send the values */
private $method = "post";
/** Create a form
@param string|null $formName The form name
@@ -55,6 +64,45 @@ class form
$this->fields = $fields;
}
/** Return the values provided by the user. Test the CSRF before continue
NEVER read the values from $_POST in your codes or CSRF will not be
checked */
public function values ()
{
$values = array ();
if ($this->method === "post")
{
if (isset ($_POST[$this->formName]))
$values = $_POST[$this->formName];
}
elseif ($this->method === "get")
{
if (isset ($_GET[$this->formName]))
$values = $_GET[$this->formName];
}
else
{
throw new Exception (_("Unknown FORM method (GET or POST allowed)"));
}
if (count ($values) !== 0)
{
// CSRF protection
try
{
$this->checkToken ($values[$this->csrfField]);
}
catch (Exception $e)
{
throw new Exception ($e->getMessage(), 500);
}
// Remove the field CSRF : can not be used outside the form
unset ($values[$this->csrfField]);
}
return $values;
}
/** Return TRUE if the value associated to a field is correct. Return an
array with a severity and a message to explain why a field is not
correct.
@@ -65,6 +113,8 @@ class form
*/
public function verify (&$fieldsVerify, $valuesVerify = NULL)
{
// TODO : Remove this function or be cleaner !
die ("FORM/VERIFY : UNUSED and dirty\n");
$ret = array ();
if ($this->debug)
echo "<pre>";
@@ -116,6 +166,7 @@ class form
$errors = array())
{
// TODO : textarea, file
$this->method = strtolower ($method);
$res = "";
$res = "<form action='#' method='$method'";
if ($this->formName != "")
@@ -430,9 +481,24 @@ class form
}
}
if ($this->csrf === TRUE)
{
$csrf = new csrf ();
$csrf->field = $this->formName."[".$this->csrfField."]";
$res .= $csrf->displayFormCSRF ();
}
$res .= "</form>\n";
return $res;
}
/** Check the token from the user */
public function checkToken ($tokenFromUser)
{
$csrf = new csrf ();
$csrf->field = $this->csrfField;
$csrf->checkToken ($tokenFromUser);
}
}
/** the definition of a formfield */
@@ -468,3 +534,52 @@ class formfield
$this->label = $label;
}
}
class csrf
{
/** CSRF protection
By default, the CSRF protection is active if a SESSION is active too.
It can be disabled if needed. An Exception is raised if the form is send
back without the token */
public $csrf=TRUE;
/** This hidden field name in HTML */
public $field = "CSRF_TOKEN";
/** The created token */
private $csrfToken = "";
/** This function return the token */
public function createToken ()
{
$l = 30; // Number of chars in token
$c = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ($s = '',
$cl = strlen($c)-1, $i = 0; $i < $l; $s .= $c[mt_rand(0, $cl)],
++$i);
$this->csrfToken = $s;
$_SESSION["domframework"]["form"]["csrf"] = $this->csrfToken;
}
/** Check if the provided token is the right token, defined last displayed
page */
public function checkToken ($tokenFromUser)
{
if ($this->csrf === FALSE )
return TRUE;
if (! isset ($_SESSION["domframework"]["form"]["csrf"]))
throw new Exception (_("No previous CSRF token : abort"));
if ($_SESSION["domframework"]["form"]["csrf"] !== $tokenFromUser)
throw new Exception (_("Invalid CSRF token provided"));
return TRUE;
}
/** Return the CSRF token in a hidden field */
public function displayFormCSRF ()
{
if ($this->csrfToken == "")
$this->createToken ();
$res = "<input type='hidden' name='$this->field' ";
$res .= "value='$this->csrfToken'/>\n";
return $res;
}
}