diff --git a/form.php b/form.php index 92f7ecc..3e73626 100644 --- a/form.php +++ b/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 "
";
@@ -116,6 +166,7 @@ class form
$errors = array())
{
// TODO : textarea, file
+ $this->method = strtolower ($method);
$res = "";
$res = "\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 = "