Просмотр исходного кода

Improve check against CSRF (#2098)

* Add CSRF for logout

* Prevent get/post requests from unknown domains

* Update changelog

* Limit connections to server port and 443 (SSL)

* Load first sys config

* Orgin is on GET not always set

* Add missing links for normal users and reset password

* Move all links to a var on top of the page

* Use HTTP_REFERER instead

* Add missing ;

* Fix version installer

Without referer exceptions list not working

* Improve error message

Include logout also in csrf check
Jaap Marcus 4 лет назад
Родитель
Сommit
02e2728586

+ 2 - 0
CHANGELOG.md

@@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file.
 
 ### Bugfixes
 - Improve the hostname check to prevent invalid hostnames or the use of an ip address (RFC1178).
+- Prevent CSRF from other domains / websites
+- Fix #2096 Hostname SSL got overwritten by mail.hostname.com certificate
 - Add small wait for /usr/bin/iptables-restore [Forum](https://forum.hestiacp.com/t/clean-install-arm64-does-not-start-after-reboot-v-start-service-iptables/4395/7)
 - Fix bug in v-change-sys-api. When using  v-change-sys-api remove and then  v-change-sys-api enable + custom release branch the resetting of api failed + no "error" output was producted
 - Improve error reporting pma-sso function

+ 1 - 0
bin/v-list-sys-config

@@ -90,6 +90,7 @@ json_list() {
         "POLICY_USER_DELETE_LOGS": "'$POLICY_USER_DELETE_LOGS'",
         "POLICY_USER_VIEW_LOGS": "'$POLICY_USER_VIEW_LOGS'",
         "POLICY_USER_CHANGE_THEME": "'$POLICY_USER_CHANGE_THEME'",
+        "POLICY_CSRF_STRICTNESS": "'$POLICY_CSRF_STRICTNESS'",
         "USE_SERVER_SMTP": "'$USE_SERVER_SMTP'",
         "SERVER_SMTP_HOST": "'$SERVER_SMTP_HOST'",
         "SERVER_SMTP_PORT": "'$SERVER_SMTP_PORT'",

+ 4 - 1
func/syshealth.sh

@@ -415,7 +415,10 @@ function syshealth_repair_system_config() {
         echo "[ ! ] Adding missing variable to hestia.conf: SERVER_SMTP_ADDR ('')"
         $BIN/v-change-sys-config-value "SERVER_SMTP_ADDR" ""
     fi    
-
+    if [ -z "$POLICY_CSRF_STRICTNESS" ]; then
+        echo "[ ! ] Adding missing variable to hestia.conf: POLICY_CSRF_STRICTNESS ('')"
+        $BIN/v-change-sys-config-value "POLICY_CSRF_STRICTNESS" "1"
+    fi  
 }
 
 # Repair System Cron Jobs

+ 1 - 0
install/hst-install-debian.sh

@@ -1953,6 +1953,7 @@ write_config_value "SERVER_SMTP_SECURITY" ""
 write_config_value "SERVER_SMTP_USER" ""
 write_config_value "SERVER_SMTP_PASSWD" ""
 write_config_value "SERVER_SMTP_ADDR" ""
+write_config_value "POLICY_CSRF_STRICTNESS" "1"
 
 #----------------------------------------------------------#
 #                  Configure PHPMailer                     #

+ 1 - 0
install/hst-install-ubuntu.sh

@@ -1965,6 +1965,7 @@ write_config_value "SERVER_SMTP_SECURITY" ""
 write_config_value "SERVER_SMTP_USER" ""
 write_config_value "SERVER_SMTP_PASSWD" ""
 write_config_value "SERVER_SMTP_ADDR" ""
+write_config_value "POLICY_CSRF_STRICTNESS" "1"
 #----------------------------------------------------------#
 #                  Configure PHPMailer                     #
 #----------------------------------------------------------#

+ 12 - 1
web/edit/server/index.php

@@ -703,12 +703,23 @@ if (!empty($_POST['save'])) {
                exec (HESTIA_CMD."v-change-sys-config-value INACTIVE_SESSION_TIMEOUT ".escapeshellarg($_POST['v_inactive_session_timeout']), $output, $return_var);
                check_return_code($return_var,$output);
                unset($output);
-               if (empty($_SESSION['error_msg'])) $v_login_style = $_POST['v_inactive_session_timeout'];
+               if (empty($_SESSION['error_msg'])) $v_inactive_session_timeout = $_POST['v_inactive_session_timeout'];
             }
             $v_security_adv = 'yes';
         }
     }
     
+   // Change POLICY_CSRF_STRICTNESS
+    if (empty($_SESSION['error_msg'])) {
+        if ($_POST['v_policy_csrf_strictness'] != $_SESSION['POLICY_CSRF_STRICTNESS']) {
+            exec (HESTIA_CMD."v-change-sys-config-value POLICY_CSRF_STRICTNESS ".escapeshellarg($_POST['v_policy_csrf_strictness']), $output, $return_var);
+            check_return_code($return_var,$output);
+            unset($output);
+            if (empty($_SESSION['error_msg'])) $v_policy_csrf_strictness = $_POST['v_inactive_session_timeout'];
+            $v_security_adv = 'yes';
+        }
+    }
+    
     // Change ENFORCE_SUBDOMAIN_OWNERSHIP
     if (empty($_SESSION['error_msg'])) {
         if ($_POST['v_enforce_subdomain_ownership'] != $_SESSION['ENFORCE_SUBDOMAIN_OWNERSHIP']) {

+ 7 - 2
web/inc/main.php

@@ -8,6 +8,7 @@ require 'vendor/autoload.php';
 
 session_start();
 
+
 define('HESTIA_CMD', '/usr/bin/sudo /usr/local/hestia/bin/');
 if ($_SESSION['RELEASE_BRANCH'] == 'release' && $_SESSION['DEBUG_MODE'] == 'false') {
     define('JS_LATEST_UPDATE','v=' . $_SESSION['VERSION']);
@@ -16,6 +17,11 @@ if ($_SESSION['RELEASE_BRANCH'] == 'release' && $_SESSION['DEBUG_MODE'] == 'fals
 }
 define('DEFAULT_PHP_VERSION', 'php-' . exec('php -r "echo (float)phpversion();"'));
 
+// Load Hestia Config directly
+load_hestia_config();
+require_once(dirname(__FILE__) . '/prevent_csrf.php');
+
+
 function destroy_sessions(){
     unset($_SESSION);
     session_unset();
@@ -61,8 +67,7 @@ if ($_SESSION['user_combined_ip'] != $user_combined_ip && $_SERVER['REMOTE_ADDR'
     header('Location: /login/');
     exit;
 }
-// Load Hestia Config directly
-    load_hestia_config();
+
 
 // Check system settings
 if ((!isset($_SESSION['VERSION'])) && (!defined('NO_AUTH_REQUIRED'))) {

+ 60 - 0
web/inc/prevent_csrf.php

@@ -0,0 +1,60 @@
+<?php
+    $check_csrf = true;
+    
+    if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/inc/mail-wrapper.php '){ $check_csrf=false; } // execute only from CLI
+    if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/reset/mail/index.php '){ $check_csrf=false; } // Localhost only
+    if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/api/index.php' ){ $check_csrf=false; } // Own check
+    if (substr($_SERVER['SCRIPT_FILENAME'], 0, 22)=='/usr/local/hestia/bin/' ){ $check_csrf=false; }
+    
+    function checkStrictness($level){
+        if ($level >= $_SESSION['POLICY_CSRF_STRICTNESS']) {
+            return true;
+        }else{
+            echo "<h1>Potential use CSRF detected</h1>\n".
+            "<p>Please disable any plugins/add-ons inside your browser or contact your system administrator. If you are the system administrator you can run v-change-sys-config-value 'POLICY_CSRF_STRICTNESS' '0' as root to disable this check.<p>".
+            "<p>If you folowed a bookmark or an static link <a href='/'>please click here</a>";
+            die();
+        }
+    }
+    function prevent_post_csrf(){
+        if ($_SERVER['REQUEST_METHOD']=='POST') {
+            $hostname = explode( ':', $_SERVER['HTTP_HOST']);
+            $port=$hostname[1];
+            $hostname=$hostname[0];
+            if (strpos($_SERVER['HTTP_ORIGIN'],gethostname()) !== false  && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ) { 
+                return checkStrictness(2);
+            }else{
+                if (strpos($_SERVER['HTTP_ORIGIN'],$hostname) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ){ 
+                    return checkStrictness(1);
+                } else {
+                    return checkStrictness(0);
+                }
+            }
+        }
+    }
+    
+    function prevent_get_csrf(){
+        if ($_SERVER['REQUEST_METHOD']=='GET') {
+            $hostname = explode( ':', $_SERVER['HTTP_HOST']);
+            $port=$hostname[1];
+            $hostname=$hostname[0];
+            //list of possible entries route and these should never be blocked
+            if (in_array($_SERVER['DOCUMENT_URI'], array('/list/user/index.php', '/login/index.php','/list/web/index.php','/list/dns/index.php','/list/mail/index.php','/list/db/index.php','/list/cron/index.php','/list/backup/index.php','/reset/index.php'))){
+                return true;
+            }
+            if (strpos($_SERVER['HTTP_REFERER'],gethostname()) !== false  && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ) { 
+                return checkStrictness(2);
+            }else{
+                if (strpos($_SERVER['HTTP_REFERER'],$hostname) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ){ 
+                    return checkStrictness(1);
+                } else {
+                    return checkStrictness(0);
+                }
+            }
+        }
+    }
+    
+    if ( $check_csrf == true){
+        prevent_post_csrf();
+        prevent_get_csrf();
+    }

+ 1 - 1
web/list/user/index.php

@@ -1,5 +1,5 @@
 <?php
-error_reporting(NULL);
+#error_reporting(NULL);
 $TAB = 'USER';
 
 // Main include

+ 6 - 1
web/logout/index.php

@@ -1,9 +1,14 @@
 <?php
 session_start();
 
-define('HESTIA_CMD', '/usr/bin/sudo /usr/local/hestia/bin/');
+// Main include
+include($_SERVER['DOCUMENT_ROOT'] . '/inc/main.php');
 
 if (!empty($_SESSION['look'])) {
+    if ((!$_GET['token']) || ($_SESSION['token'] != $_GET['token'])) {
+        header('location: /list/user/');
+        exit();
+    }
     $v_user = escapeshellarg($_SESSION['look']);
     $v_impersonator = escapeshellarg($_SESSION['user']);
     exec (HESTIA_CMD . "v-log-action system 'Warning' 'Security' 'User impersonation session ended (User: $v_user, Administrator: $v_impersonator)'", $output, $return_var);

+ 1 - 1
web/templates/includes/panel.html

@@ -84,7 +84,7 @@
 			
 			<!-- Logout -->
 			<?php if (isset($_SESSION['look']) && (!empty($_SESSION['look']))) { ?>
-				<div class="l-menu__item"><a href="/logout/" title="<?=_('Log out');?> (<?=$user?>)" class="l-profile__logout"><i class="fas fa-arrow-alt-circle-up"></i></a></div>
+				<div class="l-menu__item"><a href="/logout/?token=<?=$_SESSION['token']?>" title="<?=_('Log out');?> (<?=$user?>)" class="l-profile__logout"><i class="fas fa-arrow-alt-circle-up"></i></a></div>
 			<?php } else { ?>
 				<div class="l-menu__item"><a href="/logout/" title="<?=_('Log out');?>" class="l-profile__logout"><i class="fas fa-sign-out-alt"></i></a></div>
 			<?php } ?>

+ 16 - 0
web/templates/pages/edit_server.html

@@ -1033,6 +1033,22 @@
 														<br><br>
 													</td>
 												</tr>
+												<tr>
+													<td class="vst-text input-label">
+														<?=_('Prevent CSRF ');?>
+													</td>
+												</tr>
+												<tr>
+													<td>
+														<select class="vst-list" name="v_policy_csrf_strictness">
+															<option value="0"  <?php if($_SESSION['POLICY_CSRF_STRICTNESS'] == '0') echo 'selected' ?>><?=_('Disabled');?></option>
+															<option value="1"  <?php if($_SESSION['POLICY_CSRF_STRICTNESS'] == '1') echo 'selected' ?>><?=_('Enabled');?></option>
+															<option value="2"  <?php if($_SESSION['POLICY_CSRF_STRICTNESS'] == '2') echo 'selected' ?>><?=_('Strict');?></option>
+															
+														</select>
+														<br><br>
+													</td>
+												</tr>
 											</table>
 										</td>
 									</tr>