Skip to content

Commit 02e2728

Browse files
authored
Improve check against CSRF (hestiacp#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
1 parent 8e3cab7 commit 02e2728

File tree

12 files changed

+112
-7
lines changed

12 files changed

+112
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file.
88

99
### Bugfixes
1010
- Improve the hostname check to prevent invalid hostnames or the use of an ip address (RFC1178).
11+
- Prevent CSRF from other domains / websites
12+
- Fix #2096 Hostname SSL got overwritten by mail.hostname.com certificate
1113
- 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)
1214
- 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
1315
- Improve error reporting pma-sso function

bin/v-list-sys-config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ json_list() {
9090
"POLICY_USER_DELETE_LOGS": "'$POLICY_USER_DELETE_LOGS'",
9191
"POLICY_USER_VIEW_LOGS": "'$POLICY_USER_VIEW_LOGS'",
9292
"POLICY_USER_CHANGE_THEME": "'$POLICY_USER_CHANGE_THEME'",
93+
"POLICY_CSRF_STRICTNESS": "'$POLICY_CSRF_STRICTNESS'",
9394
"USE_SERVER_SMTP": "'$USE_SERVER_SMTP'",
9495
"SERVER_SMTP_HOST": "'$SERVER_SMTP_HOST'",
9596
"SERVER_SMTP_PORT": "'$SERVER_SMTP_PORT'",

func/syshealth.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,10 @@ function syshealth_repair_system_config() {
415415
echo "[ ! ] Adding missing variable to hestia.conf: SERVER_SMTP_ADDR ('')"
416416
$BIN/v-change-sys-config-value "SERVER_SMTP_ADDR" ""
417417
fi
418-
418+
if [ -z "$POLICY_CSRF_STRICTNESS" ]; then
419+
echo "[ ! ] Adding missing variable to hestia.conf: POLICY_CSRF_STRICTNESS ('')"
420+
$BIN/v-change-sys-config-value "POLICY_CSRF_STRICTNESS" "1"
421+
fi
419422
}
420423

421424
# Repair System Cron Jobs

install/hst-install-debian.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,7 @@ write_config_value "SERVER_SMTP_SECURITY" ""
19531953
write_config_value "SERVER_SMTP_USER" ""
19541954
write_config_value "SERVER_SMTP_PASSWD" ""
19551955
write_config_value "SERVER_SMTP_ADDR" ""
1956+
write_config_value "POLICY_CSRF_STRICTNESS" "1"
19561957

19571958
#----------------------------------------------------------#
19581959
# Configure PHPMailer #

install/hst-install-ubuntu.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,7 @@ write_config_value "SERVER_SMTP_SECURITY" ""
19651965
write_config_value "SERVER_SMTP_USER" ""
19661966
write_config_value "SERVER_SMTP_PASSWD" ""
19671967
write_config_value "SERVER_SMTP_ADDR" ""
1968+
write_config_value "POLICY_CSRF_STRICTNESS" "1"
19681969
#----------------------------------------------------------#
19691970
# Configure PHPMailer #
19701971
#----------------------------------------------------------#

web/edit/server/index.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,12 +703,23 @@
703703
exec (HESTIA_CMD."v-change-sys-config-value INACTIVE_SESSION_TIMEOUT ".escapeshellarg($_POST['v_inactive_session_timeout']), $output, $return_var);
704704
check_return_code($return_var,$output);
705705
unset($output);
706-
if (empty($_SESSION['error_msg'])) $v_login_style = $_POST['v_inactive_session_timeout'];
706+
if (empty($_SESSION['error_msg'])) $v_inactive_session_timeout = $_POST['v_inactive_session_timeout'];
707707
}
708708
$v_security_adv = 'yes';
709709
}
710710
}
711711

712+
// Change POLICY_CSRF_STRICTNESS
713+
if (empty($_SESSION['error_msg'])) {
714+
if ($_POST['v_policy_csrf_strictness'] != $_SESSION['POLICY_CSRF_STRICTNESS']) {
715+
exec (HESTIA_CMD."v-change-sys-config-value POLICY_CSRF_STRICTNESS ".escapeshellarg($_POST['v_policy_csrf_strictness']), $output, $return_var);
716+
check_return_code($return_var,$output);
717+
unset($output);
718+
if (empty($_SESSION['error_msg'])) $v_policy_csrf_strictness = $_POST['v_inactive_session_timeout'];
719+
$v_security_adv = 'yes';
720+
}
721+
}
722+
712723
// Change ENFORCE_SUBDOMAIN_OWNERSHIP
713724
if (empty($_SESSION['error_msg'])) {
714725
if ($_POST['v_enforce_subdomain_ownership'] != $_SESSION['ENFORCE_SUBDOMAIN_OWNERSHIP']) {

web/inc/main.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
session_start();
1010

11+
1112
define('HESTIA_CMD', '/usr/bin/sudo /usr/local/hestia/bin/');
1213
if ($_SESSION['RELEASE_BRANCH'] == 'release' && $_SESSION['DEBUG_MODE'] == 'false') {
1314
define('JS_LATEST_UPDATE','v=' . $_SESSION['VERSION']);
@@ -16,6 +17,11 @@
1617
}
1718
define('DEFAULT_PHP_VERSION', 'php-' . exec('php -r "echo (float)phpversion();"'));
1819

20+
// Load Hestia Config directly
21+
load_hestia_config();
22+
require_once(dirname(__FILE__) . '/prevent_csrf.php');
23+
24+
1925
function destroy_sessions(){
2026
unset($_SESSION);
2127
session_unset();
@@ -61,8 +67,7 @@ function destroy_sessions(){
6167
header('Location: /login/');
6268
exit;
6369
}
64-
// Load Hestia Config directly
65-
load_hestia_config();
70+
6671

6772
// Check system settings
6873
if ((!isset($_SESSION['VERSION'])) && (!defined('NO_AUTH_REQUIRED'))) {

web/inc/prevent_csrf.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
$check_csrf = true;
3+
4+
if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/inc/mail-wrapper.php '){ $check_csrf=false; } // execute only from CLI
5+
if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/reset/mail/index.php '){ $check_csrf=false; } // Localhost only
6+
if ( $_SERVER['SCRIPT_FILENAME'] == '/usr/local/hestia/web/api/index.php' ){ $check_csrf=false; } // Own check
7+
if (substr($_SERVER['SCRIPT_FILENAME'], 0, 22)=='/usr/local/hestia/bin/' ){ $check_csrf=false; }
8+
9+
function checkStrictness($level){
10+
if ($level >= $_SESSION['POLICY_CSRF_STRICTNESS']) {
11+
return true;
12+
}else{
13+
echo "<h1>Potential use CSRF detected</h1>\n".
14+
"<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>".
15+
"<p>If you folowed a bookmark or an static link <a href='/'>please click here</a>";
16+
die();
17+
}
18+
}
19+
function prevent_post_csrf(){
20+
if ($_SERVER['REQUEST_METHOD']=='POST') {
21+
$hostname = explode( ':', $_SERVER['HTTP_HOST']);
22+
$port=$hostname[1];
23+
$hostname=$hostname[0];
24+
if (strpos($_SERVER['HTTP_ORIGIN'],gethostname()) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ) {
25+
return checkStrictness(2);
26+
}else{
27+
if (strpos($_SERVER['HTTP_ORIGIN'],$hostname) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ){
28+
return checkStrictness(1);
29+
} else {
30+
return checkStrictness(0);
31+
}
32+
}
33+
}
34+
}
35+
36+
function prevent_get_csrf(){
37+
if ($_SERVER['REQUEST_METHOD']=='GET') {
38+
$hostname = explode( ':', $_SERVER['HTTP_HOST']);
39+
$port=$hostname[1];
40+
$hostname=$hostname[0];
41+
//list of possible entries route and these should never be blocked
42+
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'))){
43+
return true;
44+
}
45+
if (strpos($_SERVER['HTTP_REFERER'],gethostname()) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ) {
46+
return checkStrictness(2);
47+
}else{
48+
if (strpos($_SERVER['HTTP_REFERER'],$hostname) !== false && in_array($port, array('443',$_SERVER['SERVER_PORT'])) ){
49+
return checkStrictness(1);
50+
} else {
51+
return checkStrictness(0);
52+
}
53+
}
54+
}
55+
}
56+
57+
if ( $check_csrf == true){
58+
prevent_post_csrf();
59+
prevent_get_csrf();
60+
}

web/list/user/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?php
2-
error_reporting(NULL);
2+
#error_reporting(NULL);
33
$TAB = 'USER';
44

55
// Main include

web/logout/index.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
<?php
22
session_start();
33

4-
define('HESTIA_CMD', '/usr/bin/sudo /usr/local/hestia/bin/');
4+
// Main include
5+
include($_SERVER['DOCUMENT_ROOT'] . '/inc/main.php');
56

67
if (!empty($_SESSION['look'])) {
8+
if ((!$_GET['token']) || ($_SESSION['token'] != $_GET['token'])) {
9+
header('location: /list/user/');
10+
exit();
11+
}
712
$v_user = escapeshellarg($_SESSION['look']);
813
$v_impersonator = escapeshellarg($_SESSION['user']);
914
exec (HESTIA_CMD . "v-log-action system 'Warning' 'Security' 'User impersonation session ended (User: $v_user, Administrator: $v_impersonator)'", $output, $return_var);

0 commit comments

Comments
 (0)