diff options
author | Remi Collet <remi@remirepo.net> | 2019-03-27 16:06:47 +0100 |
---|---|---|
committer | Remi Collet <remi@remirepo.net> | 2019-03-27 16:06:47 +0100 |
commit | 6c1dfcb9214ecbf010719a846c8b3b8ea38f2653 (patch) | |
tree | b5ac692ee2b863e32edc58a95f182e78f1114bd7 /glpi-security2.patch | |
parent | 87c0348084cb603dd1e03474502c3ab6366e273f (diff) |
add security fix backported from 9.4.1:
[security] Bad chevrons rendering on dropdowns
[security] Iframe and forms are rendered in rich text contents
[security] Type juggling authentication bypass
[security] Malicious images upload
[security] Password token date was not reset
[security] Prevent timed attack and enforce cookie security
Diffstat (limited to 'glpi-security2.patch')
-rw-r--r-- | glpi-security2.patch | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/glpi-security2.patch b/glpi-security2.patch new file mode 100644 index 0000000..254c47a --- /dev/null +++ b/glpi-security2.patch @@ -0,0 +1,292 @@ +From 9cd45a1ec1932189fc5295e0f9978b36ab5eecaa Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 27 Mar 2019 14:55:25 +0100 +Subject: [PATCH] Fix/cookie auth (#5562) * prevent timed attack * add new + field for storing cookie token and reverse the verification (we store the + hash on our side and not client side) + +Backported from 9.4 26900a5e53a5ad347d20a947eb5f7e2b447fef9f + +Check cookie validity on glpi side + +Backported from 9.4 a3ab29c77c6fc7a45a7b0ef71c4442aee62acda6 + +Hack for DB Schema + +As 9.3.3 use dbschema 9.3.2, we can switch to 9.3.3 +Migration detection use dbversion, so will be raised +Script execution use version, which allow to keep it unchanged +More 9.4 is aware of 9.3.3 (not of 9.4) +--- + inc/auth.class.php | 19 ++++------- + inc/define.php | 2 +- + inc/update.class.php | 7 +++- + inc/user.class.php | 64 ++++++++++++++++++++++++++++++------ + install/mysql/glpi-empty.sql | 10 +++--- + install/update_932_933.php | 63 +++++++++++++++++++++++++++++++++++ + 6 files changed, 136 insertions(+), 29 deletions(-) + create mode 100644 install/update_932_933.php + +diff --git a/inc/auth.class.php b/inc/auth.class.php +index 707d7ab31..67d361653 100644 +--- a/inc/auth.class.php ++++ b/inc/auth.class.php +@@ -500,11 +500,11 @@ class Auth extends CommonGLPI { + if (count($data) === 2) { + list ($cookie_id, $cookie_token) = $data; + +- $token = User::getToken($cookie_id, 'personal_token'); ++ $user = new User(); ++ $user->getFromDB($cookie_id); ++ $hash = $user->getAuthToken('cookie_token'); + +- if ($token !== false && Auth::checkPassword($token, $cookie_token)) { +- $user = new User(); +- $user->getFromDB($cookie_id); //true if $token is not false ++ if (Auth::checkPassword($cookie_token, $hash)) { + $this->user->fields['name'] = $user->fields['name']; + return true; + } else { +@@ -848,12 +848,7 @@ class Auth extends CommonGLPI { + } + + if ($this->auth_succeded && $CFG_GLPI['login_remember_time'] > 0 && $remember_me) { +- $token = false; +- if (!empty($this->user->fields['personal_token'])) { +- $token = $this->user->fields['personal_token']; +- } else { +- $token = User::getToken($this->user->fields['id'], 'personal_token'); +- } ++ $token = $this->user->getAuthToken('cookie_token', true); + + if ($token) { + //Cookie name (Allow multiple GLPI) +@@ -861,11 +856,9 @@ class Auth extends CommonGLPI { + //Cookie session path + $cookie_path = ini_get('session.cookie_path'); + +- $hash = Auth::getPasswordHash($token); +- + $data = json_encode([ + $this->user->fields['id'], +- $hash, ++ $token, + ]); + + //Send cookie to browser +diff --git a/inc/define.php b/inc/define.php +index 78125529e..22830bc05 100644 +--- a/inc/define.php ++++ b/inc/define.php +@@ -41,7 +41,7 @@ if (substr(GLPI_VERSION, -4) === '-dev') { + ); + } else { + //for stable version +- define("GLPI_SCHEMA_VERSION", '9.3.2'); ++ define("GLPI_SCHEMA_VERSION", '9.3.3'); + } + define('GLPI_MIN_PHP', '5.6.0'); // Must also be changed in top of index.php + define('GLPI_YEAR', '2018'); +diff --git a/inc/update.class.php b/inc/update.class.php +index fec2271c0..e3da3c9f0 100644 +--- a/inc/update.class.php ++++ b/inc/update.class.php +@@ -431,7 +431,12 @@ class Update extends CommonGLPI { + case "9.3.1": + include_once "{$updir}update_931_932.php"; + update931to932(); +- break; ++ ++ case "9.3.2": ++ case "9.3.3": ++ // post 9.3.3 ++ include_once "{$updir}update_932_933.php"; ++ update932to933(); + + case GLPI_VERSION: + case GLPI_SCHEMA_VERSION: +diff --git a/inc/user.class.php b/inc/user.class.php +index 67bfc7149..d4139edfa 100644 +--- a/inc/user.class.php ++++ b/inc/user.class.php +@@ -4595,26 +4595,70 @@ class User extends CommonDBTM { + } + + +- /** ++ /** ++ * Get token of a user. If it does not exists then generate it. ++ * ++ * @since 9.4 ++ * ++ * @param string $field the field storing the token ++ * @param boolean $force_new force generation of a new token ++ * ++ * @return string|false token or false in case of error ++ */ ++ public function getAuthToken($field = 'personal_token', $force_new = false) { ++ global $CFG_GLPI; ++ ++ if ($this->isNewItem()) { ++ return false; ++ } ++ ++ // check date validity for cookie token ++ $outdated = false; ++ if ($field === 'cookie_token') { ++ $date_create = new DateTime($this->fields[$field."_date"]); ++ $date_expir = $date_create->add(new DateInterval('PT'.$CFG_GLPI["login_remember_time"].'S')); ++ ++ if ($date_expir < new DateTime()) { ++ $outdated = true; ++ } ++ } ++ ++ // token exists, is not oudated, and we may use it ++ if (!empty($this->fields[$field]) && !$force_new && !$outdated) { ++ return $this->fields[$field]; ++ } ++ ++ // else get a new token ++ $token = self::getUniqueToken($field); ++ ++ // for cookie token, we need to store it hashed ++ $hash = $token; ++ if ($field === 'cookie_token') { ++ $hash = Auth::getPasswordHash($token); ++ } ++ ++ // save this token in db ++ $this->update(['id' => $this->getID(), ++ $field => $hash, ++ $field . "_date" => $_SESSION['glpi_currenttime']]); ++ ++ return $token; ++ } ++ ++/** + * Get token of a user. If not exists generate it. + * + * @param integer $ID User ID + * @param string $field Field storing the token ++ * @param boolean $force_new force generation of a new token + * + * @return string|boolean User token, false if user does not exist + */ +- static function getToken($ID, $field = 'personal_token') { ++ static function getToken($ID, $field = 'personal_token', $force_new = false) { + + $user = new self(); + if ($user->getFromDB($ID)) { +- if (!empty($user->fields[$field])) { +- return $user->fields[$field]; +- } +- $token = self::getUniqueToken($field); +- $user->update(['id' => $user->getID(), +- $field => $token, +- $field . "_date" => $_SESSION['glpi_currenttime']]); +- return $user->fields[$field]; ++ return $user->getAuthToken($field, $force_new); + } + + return false; +diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql +index abfe14600..14d6976c9 100644 +--- a/install/mysql/glpi-empty.sql ++++ b/install/mysql/glpi-empty.sql +@@ -8850,6 +8850,8 @@ CREATE TABLE `glpi_users` ( + `personal_token_date` datetime DEFAULT NULL, + `api_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + `api_token_date` datetime DEFAULT NULL, ++ `cookie_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, ++ `cookie_token_date` datetime DEFAULT NULL, + `display_count_on_home` int(11) DEFAULT NULL, + `notification_to_myself` tinyint(1) DEFAULT NULL, + `duedateok_color` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, +@@ -8900,10 +8902,10 @@ CREATE TABLE `glpi_users` ( + KEY `sync_field` (`sync_field`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); + + ### Dump table glpi_usertitles + +diff --git a/install/update_932_933.php b/install/update_932_933.php +new file mode 100644 +index 000000000..240c5cb00 +--- /dev/null ++++ b/install/update_932_933.php +@@ -0,0 +1,63 @@ ++<?php ++/** ++ * --------------------------------------------------------------------- ++ * GLPI - Gestionnaire Libre de Parc Informatique ++ * Copyright (C) 2015-2017 Teclib' and contributors. ++ * ++ * http://glpi-project.org ++ * ++ * based on GLPI - Gestionnaire Libre de Parc Informatique ++ * Copyright (C) 2003-2014 by the INDEPNET Development Team. ++ * ++ * --------------------------------------------------------------------- ++ * ++ * LICENSE ++ * ++ * This file is part of GLPI. ++ * ++ * GLPI is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * GLPI is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GLPI. If not, see <http://www.gnu.org/licenses/>. ++ * --------------------------------------------------------------------- ++ */ ++ ++/** @file ++* @brief ++*/ ++ ++/** ++ * Update from 9.3.2 to 9.3.3 (DB schema version, introduced post 9.3.3) ++ * ++ * @return bool for success (will die for most error) ++**/ ++function update932to933() { ++ global $DB, $migration, $CFG_GLPI; ++ ++ $current_config = Config::getConfigurationValues('core'); ++ $updateresult = true; ++ $ADDTODISPLAYPREF = []; ++ ++ //TRANS: %s is the number of new version ++ $migration->displayTitle(sprintf(__('Update to %s'), '9.3.3')); ++ $migration->setVersion('9.3.3'); ++ ++ // Create a dedicated token for rememberme process ++ if (!$DB->fieldExists('glpi_users', 'cookie_token')) { ++ $migration->addField('glpi_users', 'cookie_token', 'string', ['after' => 'api_token_date']); ++ $migration->addField('glpi_users', 'cookie_token_date', 'datetime', ['after' => 'cookie_token']); ++ } ++ ++ // ************ Keep it at the end ************** ++ $migration->executeMigration(); ++ ++ return $updateresult; ++} +-- +2.20.1 + |