From d9bdfaf1acbf0b2b4df4a641f3478df0feed95eb Mon Sep 17 00:00:00 2001 From: Benjamin Sonntag Date: Thu, 19 May 2016 17:04:49 +0200 Subject: [PATCH] [wip] adding csrf form management, to be added everywhere --- bureau/class/functions.php | 50 ++++++++++++++++++++++++++++++++++++++ install/upgrades/3.4.5.sql | 10 ++++++++ 2 files changed, 60 insertions(+) create mode 100644 install/upgrades/3.4.5.sql diff --git a/bureau/class/functions.php b/bureau/class/functions.php index 03328db8..b2b8398f 100644 --- a/bureau/class/functions.php +++ b/bureau/class/functions.php @@ -1073,3 +1073,53 @@ function panel_unlock() { function panel_islocked() { return file_exists(ALTERNC_LOCK_PANEL); } + + +/** Give a new CSRF uniq token for a form + * the session must be up since the CSRF is linked + * to the session cookie. We also need the $db pdo object + * @return the csrf cookie to add into a csrf hidden field in your form + */ +function csrf_get() { + global $db; + if (!isset($_SESSION["csrf"])) { + $_SESSION["csrf"]=md5(rand().rand().rand()); + } + $token=md5(rand().rand().rand()); + $db->query("INSERT INTO csrf SET cookie=?, token=?, created=NOW(), used=0;",array($_SESSION["csrf"],$token)); + return $token; +} + +/** Check a CSRF token against the current session + * a token can be only checked once, it's disabled then + * @param $token string the token to check in the DB + session + * @return $result integer 0 for invalid token, 1 for good token, -1 for expired token (already used) + * if a token is invalid or expired, an $err is raised, that can be displayed + */ +function csrf_check($token) { + global $db,$err; + if (!isset($_SESSION["csrf"])) { + $err->raise("functions", _("The posted form token is incorrect. Maybe you need to allow cookies")); + return 0; // no csrf cookie :/ + } + if (!preg_match('#^[0-9a-f]{32}$#',$token)) { + $err->raise("functions", _("The posted form token is invalid")); + return 0; // invalid csrf token + } + if (!preg_match('#^[0-9a-f]{32}$#',$_SESSION["csrf"])) { + unset($_SESSION["csrf"]); + $err->raise("functions", _("Your cookie is invalid")); + return 0; // invalid csrf cookie + } + $db->query("SELECT used FROM csrf WHERE cookie=? AND token=?;",array($_SESSION["csrf"],$token)); + if (!$db->next_record()) { + $err->raise("functions", _("Your token is invalid")); + return 0; // invalid csrf cookie + } + if ($db->f("used")) { + $err->raise("functions", _("Your token is expired. Please refill the form.")); + return -1; // expired + } + $db->query("UPDATE csrf SET used=1 WHERE cookie=? AND token=?;",array($_SESSION["csrf"],$token)); + return 1; +} \ No newline at end of file diff --git a/install/upgrades/3.4.5.sql b/install/upgrades/3.4.5.sql new file mode 100644 index 00000000..1d8263fd --- /dev/null +++ b/install/upgrades/3.4.5.sql @@ -0,0 +1,10 @@ + + +CREATE TABLE IF NOT EXISTS `csrf` ( + `cookie` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `token` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `created` datetime NOT NULL, + `used` tinyint(3) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='csrf tokens for AlternC forms'; + +ALTER TABLE `csrf` ADD PRIMARY KEY (`session`,`token`), ADD KEY `created` (`created`);