From 62ffce88d51a9922ac2d93c7514cb732a3894c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come@opensides.be> Date: Mon, 4 Jun 2018 17:10:29 +0200 Subject: [PATCH] Merge branch '5840-security-vulnerability-cross-site-request-forgery' into '1.3-dev' Resolve "Security Vulnerability: Cross Site Request Forgery" See merge request fusiondirectory/fd!280 (cherry picked from commit 5edd2e32473bec27575719bff751308e57167731) d8dbd130 :sparkels: feat(core) Add CSRF protection token 6e31f486 :sparkles: feat(core) Reject CSRF based on HEADER values d9089973 :ambulance: fix(core) Remove useless line in CSRFProtection 3b51b48c :ambulance: fix(core) Use FusionDirectoryException instead of Exception 1ac4c8b5 :ambulance: fix(core) sonar fix --- html/main.php | 8 ++-- html/setup.php | 3 ++ ihtml/themes/breezy/framework.tpl | 1 + include/class_CSRFProtection.inc | 69 +++++++++++++++++++++++++++++++ setup/setup_frame.tpl | 1 + 5 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 include/class_CSRFProtection.inc diff --git a/html/main.php b/html/main.php index 571ad1826..77b69f4cd 100644 --- a/html/main.php +++ b/html/main.php @@ -1,9 +1,8 @@ <?php - /* This code is part of FusionDirectory (http://www.fusiondirectory.org/) Copyright (C) 2003-2010 Cajus Pollmeier - Copyright (C) 2011-2016 FusionDirectory + Copyright (C) 2011-2018 FusionDirectory This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -54,6 +53,8 @@ if (!session::global_is_set('connected')) { exit; } +CSRFProtection::check(); + $ui = session::global_get('ui'); $config = session::global_get('config'); @@ -318,7 +319,8 @@ if (session::is_set('errors') && session::get('errors') != "") { $focus = '<script type="text/javascript">'; $focus .= 'next_msg_dialog();'; $focus .= '</script>'; -$smarty->assign("focus", $focus); +$smarty->assign('focus', $focus); +$smarty->assign('CSRFtoken', CSRFProtection::getToken()); /* Set channel if needed */ //TODO: * move all global session calls to global_ diff --git a/html/setup.php b/html/setup.php index 183840d0c..5a0e39c1f 100644 --- a/html/setup.php +++ b/html/setup.php @@ -49,6 +49,8 @@ session::start(); session::global_set('DEBUGLEVEL', 0); session::set('errorsAlreadyPosted', array()); +CSRFProtection::check(); + /* Attribute initialization, reset errors */ reset_errors(); @@ -123,6 +125,7 @@ $smarty->assign("navigation", $setup->get_navigation_html()); $smarty->assign("headline_image", $setup->get_header_image()); $smarty->assign("headline", $setup->get_header_text()); $smarty->assign("focus", $focus); +$smarty->assign('CSRFtoken', CSRFProtection::getToken()); $smarty->assign("msg_dialogs", msg_dialog::get_dialogs()); if ($error_collector != "") { diff --git a/ihtml/themes/breezy/framework.tpl b/ihtml/themes/breezy/framework.tpl index d1061fe28..ba6b98d15 100644 --- a/ihtml/themes/breezy/framework.tpl +++ b/ihtml/themes/breezy/framework.tpl @@ -55,6 +55,7 @@ {$errors} {$focus} <input type="hidden" name="php_c_check" value="1"/> + <input type="hidden" name="CSRFtoken" value="{$CSRFtoken}"/> </form> diff --git a/include/class_CSRFProtection.inc b/include/class_CSRFProtection.inc new file mode 100644 index 000000000..a2d814888 --- /dev/null +++ b/include/class_CSRFProtection.inc @@ -0,0 +1,69 @@ +<?php +/* + This code is part of FusionDirectory (http://www.fusiondirectory.org/) + Copyright (C) 2017-2018 FusionDirectory + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +class CSRFProtection +{ + public static function check() + { + if (empty($_POST)) { + return; + } + if (empty($_POST['CSRFtoken'])) { + throw new FusionDirectoryException('CSRF protection token missing'); + } + + static::checkHeaders(); + + if ($_POST['CSRFtoken'] !== static::getToken()) { + throw new FusionDirectoryException('CSRF protection token invalid'); + } + } + + public static function getToken() + { + if (!session::is_set('CSRFtoken')) { + session::set('CSRFtoken', standAlonePage::generateRandomHash()); + } + return session::get('CSRFtoken'); + } + + public static function checkHeaders() + { + $origin = FALSE; + if (!empty($_SERVER['HTTP_ORIGIN'])) { + $origin = $_SERVER['HTTP_ORIGIN']; + } elseif (!empty($_SERVER['HTTP_REFERER'])) { + $origin = $_SERVER['HTTP_REFERER']; + } + if ($origin) { + $origin = preg_replace('|^[^/]+://([^/]+)(/.*)?$|', '\1', $origin); + $target = FALSE; + if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) { + $target = $_SERVER['HTTP_X_FORWARDED_HOST']; + } else + if (!empty($_SERVER['HTTP_HOST'])) { + $target = $_SERVER['HTTP_HOST']; + } + if ($target && !hash_equals($origin, $target)) { + throw new FusionDirectoryException('CSRF detected: origin and target are not matching ('.$origin.' != '.$target.')'); + } + } + } +} diff --git a/setup/setup_frame.tpl b/setup/setup_frame.tpl index 071f5365c..03dd16c50 100644 --- a/setup/setup_frame.tpl +++ b/setup/setup_frame.tpl @@ -39,6 +39,7 @@ {$errors} {$focus} <input type="hidden" name="setup_goto_step" value=""/> + <input type="hidden" name="CSRFtoken" value="{$CSRFtoken}"/> </form> </body> -- GitLab