From 5af0cfd99a13fda9afad3380b0c50a3428acd299 Mon Sep 17 00:00:00 2001 From: Till Brehm <tbrehm@ispconfig.org> Date: Wed, 3 Jun 2015 18:14:07 +0200 Subject: [PATCH] Extended the CSRF check. --- interface/lib/classes/auth.inc.php | 50 +++++++++++++++++++ interface/lib/classes/tform.inc.php | 8 ++- interface/web/admin/language_add.php | 9 ++++ interface/web/admin/language_complete.php | 8 +++ interface/web/admin/language_edit.php | 9 ++++ interface/web/admin/language_import.php | 9 ++++ .../web/admin/remote_action_ispcupdate.php | 9 ++++ .../web/admin/remote_action_osupdate.php | 9 ++++ interface/web/client/client_message.php | 10 +++- .../web/themes/default/templates/form.tpl.htm | 4 +- interface/web/tools/dns_import_tupa.php | 7 +++ interface/web/tools/import_ispconfig.php | 9 ++++ interface/web/tools/import_plesk.php | 7 +++ interface/web/tools/resync.php | 10 ++++ interface/web/vm/openvz_action.php | 10 ++++ 15 files changed, 165 insertions(+), 3 deletions(-) diff --git a/interface/lib/classes/auth.inc.php b/interface/lib/classes/auth.inc.php index 9abb535012..fe63fc6088 100644 --- a/interface/lib/classes/auth.inc.php +++ b/interface/lib/classes/auth.inc.php @@ -201,6 +201,56 @@ class auth { $salt.="$"; return crypt($cleartext_password, $salt); } + + public function csrf_token_get($form_name) { + /* CSRF PROTECTION */ + // generate csrf protection id and key + $_csrf_id = uniqid($form_name . '_'); // form id + $_csrf_key = sha1(uniqid(microtime(true), true)); // the key + if(!isset($_SESSION['_csrf'])) $_SESSION['_csrf'] = array(); + if(!isset($_SESSION['_csrf_timeout'])) $_SESSION['_csrf_timeout'] = array(); + $_SESSION['_csrf'][$_csrf_id] = $_csrf_key; + $_SESSION['_csrf_timeout'][$_csrf_id] = time() + 3600; // timeout hash in 1 hour + + return array('csrf_id' => $_csrf_id,'csrf_key' => $_csrf_key); + } + + public function csrf_token_check() { + global $app; + + if(isset($_POST) && is_array($_POST)) { + $_csrf_valid = false; + if(isset($_POST['_csrf_id']) && isset($_POST['_csrf_key'])) { + $_csrf_id = trim($_POST['_csrf_id']); + $_csrf_key = trim($_POST['_csrf_key']); + if(isset($_SESSION['_csrf']) && isset($_SESSION['_csrf'][$_csrf_id]) && isset($_SESSION['_csrf_timeout']) && isset($_SESSION['_csrf_timeout'][$_csrf_id])) { + if($_SESSION['_csrf'][$_csrf_id] === $_csrf_key && $_SESSION['_csrf_timeout'] >= time()) $_csrf_valid = true; + } + } + if($_csrf_valid !== true) { + $app->log('CSRF attempt blocked. Referer: ' . (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'unknown'), LOGLEVEL_WARN); + $app->error($app->lng('err_csrf_attempt_blocked')); + } + $_SESSION['_csrf'][$_csrf_id] = null; + $_SESSION['_csrf_timeout'][$_csrf_id] = null; + unset($_SESSION['_csrf'][$_csrf_id]); + unset($_SESSION['_csrf_timeout'][$_csrf_id]); + + if(isset($_SESSION['_csrf_timeout']) && is_array($_SESSION['_csrf_timeout'])) { + $to_unset = array(); + foreach($_SESSION['_csrf_timeout'] as $_csrf_id => $timeout) { + if($timeout < time()) $to_unset[] = $_csrf_id; + } + foreach($to_unset as $_csrf_id) { + $_SESSION['_csrf'][$_csrf_id] = null; + $_SESSION['_csrf_timeout'][$_csrf_id] = null; + unset($_SESSION['_csrf'][$_csrf_id]); + unset($_SESSION['_csrf_timeout'][$_csrf_id]); + } + unset($to_unset); + } + } + } } diff --git a/interface/lib/classes/tform.inc.php b/interface/lib/classes/tform.inc.php index d0bb7d128f..1717419794 100644 --- a/interface/lib/classes/tform.inc.php +++ b/interface/lib/classes/tform.inc.php @@ -386,12 +386,17 @@ class tform { /* CSRF PROTECTION */ // generate csrf protection id and key - $_csrf_id = uniqid($this->formDef['name'] . '_'); + /*$_csrf_id = uniqid($this->formDef['name'] . '_'); $_csrf_value = sha1(uniqid(microtime(true), true)); if(!isset($_SESSION['_csrf'])) $_SESSION['_csrf'] = array(); if(!isset($_SESSION['_csrf_timeout'])) $_SESSION['_csrf_timeout'] = array(); $_SESSION['_csrf'][$_csrf_id] = $_csrf_value; $_SESSION['_csrf_timeout'][$_csrf_id] = time() + 3600; // timeout hash in 1 hour + */ + $csrf_token = $app->auth->csrf_token_get($this->formDef['name']); + $_csrf_id = $csrf_token['csrf_id']; + $_csrf_value = $csrf_token['csrf_key']; + $this->formDef['tabs'][$tab]['fields']['_csrf_id'] = array( 'datatype' => 'VARCHAR', 'formtype' => 'TEXT', @@ -669,6 +674,7 @@ class tform { //$this->errorMessage = ''; /* CSRF PROTECTION */ + if(isset($_POST) && is_array($_POST)) { $_csrf_valid = false; if(isset($_POST['_csrf_id']) && isset($_POST['_csrf_key'])) { diff --git a/interface/web/admin/language_add.php b/interface/web/admin/language_add.php index 8c488c34c9..f58a2db16d 100644 --- a/interface/web/admin/language_add.php +++ b/interface/web/admin/language_add.php @@ -65,6 +65,10 @@ $app->tpl->setVar('language_option', $language_option); $app->tpl->setVar('error', $error); if(isset($_POST['lng_new']) && strlen($_POST['lng_new']) == 2 && $error == '') { + + //* CSRF Check + $app->auth->csrf_token_check(); + $lng_new = $_POST['lng_new']; if(!preg_match("/^[a-z]{2}$/i", $lng_new)) die('unallowed characters in language name.'); @@ -94,6 +98,11 @@ if(isset($_POST['lng_new']) && strlen($_POST['lng_new']) == 2 && $error == '') { $app->tpl->setVar('msg', $msg); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('language_add'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + //* load language file $lng_file = 'lib/lang/'.$_SESSION['s']['language'].'_language_add.lng'; include $lng_file; diff --git a/interface/web/admin/language_complete.php b/interface/web/admin/language_complete.php index d8f4bbda86..d28e89aa25 100644 --- a/interface/web/admin/language_complete.php +++ b/interface/web/admin/language_complete.php @@ -67,6 +67,9 @@ $app->tpl->setVar('error', $error); // Export the language file if(isset($_POST['lng_select']) && $error == '') { + //* CSRF Check + $app->auth->csrf_token_check(); + // complete the global langauge file merge_langfile(ISPC_LIB_PATH."/lang/".$selected_language.".lng", ISPC_LIB_PATH."/lang/en.lng"); @@ -157,6 +160,11 @@ function merge_langfile($langfile, $masterfile) { $app->tpl->setVar('msg', $msg); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('language_merge'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + //* load language file $lng_file = 'lib/lang/'.$_SESSION['s']['language'].'_language_complete.lng'; include $lng_file; diff --git a/interface/web/admin/language_edit.php b/interface/web/admin/language_edit.php index 7d83b9bb74..c94a5eb280 100644 --- a/interface/web/admin/language_edit.php +++ b/interface/web/admin/language_edit.php @@ -55,6 +55,10 @@ $msg = ''; //* Save data if(isset($_POST['records']) && is_array($_POST['records'])) { + + //* CSRF Check + $app->auth->csrf_token_check(); + $file_content = "<?php\n"; foreach($_POST['records'] as $key => $val) { $val = stripslashes($val); @@ -93,6 +97,11 @@ if(isset($wb) && is_array($wb)) { unset($wb); } +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('language_edit'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + //* load language file $lng_file = 'lib/lang/'.$_SESSION['s']['language'].'_language_edit.lng'; diff --git a/interface/web/admin/language_import.php b/interface/web/admin/language_import.php index d53575ba26..00d105cc67 100644 --- a/interface/web/admin/language_import.php +++ b/interface/web/admin/language_import.php @@ -129,6 +129,10 @@ $error = ''; // Export the language file if(isset($_FILES['file']['name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { + + //* CSRF Check + $app->auth->csrf_token_check(); + $lines = file($_FILES['file']['tmp_name']); // initial check $parts = explode('|', $lines[0]); @@ -183,6 +187,11 @@ if(isset($_FILES['file']['name']) && is_uploaded_file($_FILES['file']['tmp_name' $app->tpl->setVar('msg', $msg); $app->tpl->setVar('error', $error); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('language_import'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + //* load language file $lng_file = 'lib/lang/'.$_SESSION['s']['language'].'_language_import.lng'; include $lng_file; diff --git a/interface/web/admin/remote_action_ispcupdate.php b/interface/web/admin/remote_action_ispcupdate.php index 32bf0c4333..d207dd0680 100644 --- a/interface/web/admin/remote_action_ispcupdate.php +++ b/interface/web/admin/remote_action_ispcupdate.php @@ -66,6 +66,10 @@ $msg = ''; //* Note: Disabled post action if (1 == 0 && isset($_POST['server_select'])) { + + //* CSRF Check + $app->auth->csrf_token_check(); + $server = $_POST['server_select']; $servers = array(); if ($server == '*') { @@ -95,6 +99,11 @@ if (1 == 0 && isset($_POST['server_select'])) { $app->tpl->setVar('msg', $msg); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('ispupdate'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl->setVar($wb); $app->tpl_defaults(); diff --git a/interface/web/admin/remote_action_osupdate.php b/interface/web/admin/remote_action_osupdate.php index 61c6c23823..0d42308902 100644 --- a/interface/web/admin/remote_action_osupdate.php +++ b/interface/web/admin/remote_action_osupdate.php @@ -62,6 +62,10 @@ $msg = ''; * If the user wants to do the action, write this to our db */ if (isset($_POST['server_select'])) { + + //* CSRF Check + $app->auth->csrf_token_check(); + $server = $_POST['server_select']; $servers = array(); if ($server == '*') { @@ -91,6 +95,11 @@ if (isset($_POST['server_select'])) { $app->tpl->setVar('msg', $msg); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('osupdate'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl->setVar($wb); $app->tpl_defaults(); diff --git a/interface/web/client/client_message.php b/interface/web/client/client_message.php index 5707e88206..d38fc9352c 100644 --- a/interface/web/client/client_message.php +++ b/interface/web/client/client_message.php @@ -51,7 +51,10 @@ $error = ''; //* Save data if(isset($_POST) && count($_POST) > 1) { - + + //* CSRF Check + $app->auth->csrf_token_check(); + //* Check values if(!preg_match("/^\w+[\w\.\-\+]*\w{0,}@\w+[\w.-]*\w+\.[a-zA-Z0-9\-]{2,30}$/i", $_POST['sender'])) $error .= $wb['sender_invalid_error'].'<br />'; if(empty($_POST['subject'])) $error .= $wb['subject_invalid_error'].'<br />'; @@ -161,6 +164,11 @@ if(!empty($field_names) && is_array($field_names)){ } $app->tpl->setVar('message_variables', trim($message_variables)); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('client_message'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl->setVar('okmsg', $msg); $app->tpl->setVar('error', $error); diff --git a/interface/web/themes/default/templates/form.tpl.htm b/interface/web/themes/default/templates/form.tpl.htm index 429bfd9f24..a2d3dfc447 100644 --- a/interface/web/themes/default/templates/form.tpl.htm +++ b/interface/web/themes/default/templates/form.tpl.htm @@ -1 +1,3 @@ -<tmpl_dyninclude name="content_tpl"> \ No newline at end of file +<tmpl_dyninclude name="content_tpl"> +<input type="hidden" name="_csrf_id" value="{tmpl_var name='_csrf_id'}" /> +<input type="hidden" name="_csrf_key" value="{tmpl_var name='_csrf_key'}" /> \ No newline at end of file diff --git a/interface/web/tools/dns_import_tupa.php b/interface/web/tools/dns_import_tupa.php index 775d515289..aea6c4300f 100644 --- a/interface/web/tools/dns_import_tupa.php +++ b/interface/web/tools/dns_import_tupa.php @@ -45,6 +45,9 @@ $error = ''; // Resyncing dns zones if(isset($_POST['start']) && $_POST['start'] == 1) { + + //* CSRF Check + $app->auth->csrf_token_check(); //* Set variable sin template $app->tpl->setVar('dbhost', $_POST['dbhost']); @@ -151,6 +154,10 @@ if(isset($_POST['start']) && $_POST['start'] == 1) { $app->tpl->setVar('msg', $msg); $app->tpl->setVar('error', $error); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('dns_import'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); $app->tpl_defaults(); $app->tpl->pparse(); diff --git a/interface/web/tools/import_ispconfig.php b/interface/web/tools/import_ispconfig.php index 75e59929df..b2ce4cc8a5 100644 --- a/interface/web/tools/import_ispconfig.php +++ b/interface/web/tools/import_ispconfig.php @@ -49,6 +49,10 @@ include $lng_file; $app->tpl->setVar($wb); if(isset($_POST['connected'])) { + + //* CSRF Check + $app->auth->csrf_token_check(); + $connected = $app->functions->intval($_POST['connected']); if($connected == 0) { @@ -133,6 +137,11 @@ $app->tpl->setVar('remote_session_id', $remote_session_id); $app->tpl->setVar('msg', $msg); $app->tpl->setVar('error', $error); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('ispconfig_import'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl_defaults(); $app->tpl->pparse(); diff --git a/interface/web/tools/import_plesk.php b/interface/web/tools/import_plesk.php index 0be88b583e..61922e2b30 100644 --- a/interface/web/tools/import_plesk.php +++ b/interface/web/tools/import_plesk.php @@ -144,6 +144,9 @@ $error = ''; // Start migrating plesk data if(isset($_POST['start']) && $_POST['start'] == 1) { + //* CSRF Check + $app->auth->csrf_token_check(); + //* Set variable sin template $app->tpl->setVar('dbhost', $_POST['dbhost']); $app->tpl->setVar('dbname', $_POST['dbname']); @@ -1209,6 +1212,10 @@ if(isset($_POST['start']) && $_POST['start'] == 1) { $app->tpl->setVar('msg', $msg); $app->tpl->setVar('error', $error); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('plesk_import'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); $app->tpl_defaults(); $app->tpl->pparse(); diff --git a/interface/web/tools/resync.php b/interface/web/tools/resync.php index 1191585ff5..36d4fab341 100644 --- a/interface/web/tools/resync.php +++ b/interface/web/tools/resync.php @@ -48,6 +48,11 @@ $lng_file = 'lib/lang/'.$_SESSION['s']['language'].'_resync.lng'; include $lng_file; $app->tpl->setVar($wb); +if(isset($_POST) && count($_POST) > 1) { + //* CSRF Check + $app->auth->csrf_token_check(); +} + //* Resyncing websites if(isset($_POST['resync_sites']) && $_POST['resync_sites'] == 1) { $db_table = 'web_domain'; @@ -217,6 +222,11 @@ if(isset($_POST['resync_client']) && $_POST['resync_client'] == 1) { $app->tpl->setVar('msg', $msg); $app->tpl->setVar('error', $error); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('tools_resync'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl_defaults(); $app->tpl->pparse(); diff --git a/interface/web/vm/openvz_action.php b/interface/web/vm/openvz_action.php index 6e090d7468..b387ef3d41 100644 --- a/interface/web/vm/openvz_action.php +++ b/interface/web/vm/openvz_action.php @@ -17,6 +17,11 @@ $notify_msg = ''; if($vm_id == 0) die('Invalid VM ID'); +if(isset($_POST) && count($_POST) > 1) { + //* CSRF Check + $app->auth->csrf_token_check(); +} + $vm = $app->db->queryOneRecord("SELECT server_id, veid FROM openvz_vm WHERE vm_id = $vm_id"); $veid = $app->functions->intval($vm['veid']); $server_id = $app->functions->intval($vm['server_id']); @@ -141,6 +146,11 @@ if($action == 'show') { $app->tpl->setVar($options); $app->tpl->setVar('error', $error_msg); +//* SET csrf token +$csrf_token = $app->auth->csrf_token_get('openvz_action'); +$app->tpl->setVar('_csrf_id',$csrf_token['csrf_id']); +$app->tpl->setVar('_csrf_key',$csrf_token['csrf_key']); + $app->tpl_defaults(); $app->tpl->pparse(); -- GitLab