From cba4fcc57cc211df7e288529bca29446d21a0ddc Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Sun, 1 Jun 2014 06:03:52 +0000 Subject: [PATCH] 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 --- form.php | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) 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 = "
formName != "") @@ -430,9 +481,24 @@ class form } } + if ($this->csrf === TRUE) + { + $csrf = new csrf (); + $csrf->field = $this->formName."[".$this->csrfField."]"; + $res .= $csrf->displayFormCSRF (); + } + $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 = "