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:
115
form.php
115
form.php
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user