* @license BSD */ /** 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 */ class csrf { /** Allow to disable the csrf protection */ public $csrf = TRUE; /** This hidden field name in HTML */ public $field = "CSRF_TOKEN"; /** The created token */ private $csrfToken = ""; /** Timeout of the CSRF token : 3600s by default (maximum time allowed to * enter information in form and submit) */ private $csrfTimeout = 3600; /** Manage the singleton */ public function __construct () // {{{ { if (isset ($GLOBALS["domframework"]["csrf"])) { $this->csrfToken = $GLOBALS["domframework"]["csrf"]->csrfToken; $this->field = $GLOBALS["domframework"]["csrf"]->field; $this->csrfTimeout = $GLOBALS["domframework"]["csrf"]->csrfTimeout; } else { $GLOBALS["domframework"]["csrf"] = $this; } } // }}} /** Get / Set the status of the CSRF protection * @param boolean|null $val The value to set/get if null */ public function csrfState ($val = null) // {{{ { if ($val === null) return $this->csrf; $this->csrf = !! $val; $GLOBALS["domframework"]["csrf"] = $this; return $this; } // }}} /** Get / Set the name of the field in HTML * @param string|null $val The value to set/get if null */ public function field ($val = null) // {{{ { if ($val === null) return $this->field; $this->field = $val; $GLOBALS["domframework"]["csrf"] = $this; return $this; } // }}} /** 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"]["csrf"][$this->csrfToken] = microtime (TRUE); $GLOBALS["domframework"]["csrf"] = $this; return $this->csrfToken; } // }}} /** Check if the provided token is the right token, defined last displayed * page * @param string $tokenFromUser The value csrf the user's token */ public function checkToken ($tokenFromUser) // {{{ { if ($this->csrf === FALSE ) return TRUE; // Migrate from unique format to multiple CSRF tokens format // The new format is : array (token => the last used time) if (isset ($_SESSION["domframework"]["csrf"]["csrf"]) && isset ($_SESSION["domframework"]["csrf"]["csrfStart"])) { $_SESSION["domframework"]["csrf"] = array ( $_SESSION["domframework"]["csrf"]["csrf"] => $_SESSION["domframework"]["csrf"]["csrfStart"] ); unset ($_SESSION["domframework"]["csrf"]["csrfStart"]); } if (! isset ($_SESSION["domframework"]["csrf"])) { throw new \Exception (dgettext ("domframework", "No previous CSRF token found in session ". "(maybe a new session after expiration ?) : abort"), 406); } if (! key_exists ($tokenFromUser, $_SESSION["domframework"]["csrf"])) { throw new \Exception (dgettext ("domframework", "Invalid CSRF token provided"), 406); } if (($_SESSION["domframework"]["csrf"][$tokenFromUser] + $this->csrfTimeout) < microtime (TRUE)) { throw new \Exception (dgettext ("domframework", "Obsolete CSRF token provided"), 406); } // Clean expired tokens (2 times the $this->csrfTimeout) foreach ($_SESSION["domframework"]["csrf"] as $token => $timeout) { if ($timeout + 2 * $this->csrfTimeout < time ()) unset ($_SESSION["domframework"]["csrf"][$token]); } return TRUE; } // }}} /** Return the CSRF token in a hidden field */ public function displayFormCSRF () // {{{ { if ($this->csrfToken == "") $this->createToken (); $res = "csrfToken === "") $this->createToken (); return $this->csrfToken; } // }}} /** Add more time to existing CSRF token * @param string $tokenFromUser The existing token */ public function extendToken ($tokenFromUser) // {{{ { $this->checkToken ($tokenFromUser); $_SESSION["domframework"]["csrf"][$tokenFromUser] = microtime (TRUE); return true; } // }}} /** Check an existing token, then delete it * @param string $tokenFromUser The existing token */ public function checkThenDeleteToken ($tokenFromUser) // {{{ { $this->checkToken ($tokenFromUser); unset ($_SESSION["domframework"]["csrf"][$tokenFromUser]); return true; } // }}} }