aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2022-03-23 18:38:03 +0000
committerMario <mario@mariovavti.com>2022-03-23 18:38:03 +0000
commita41c7caa182117b2b7b820550cc20dff8be2c0f0 (patch)
tree19611241fd496b778c2f412ab9ebcc4fb34843bd
parentbddeab3ac11efaf786ddb2a6ce3f73d8c06790ab (diff)
parentb3ca31bce7ed0dd5777458005718ba96985cbdc2 (diff)
downloadvolse-hubzilla-a41c7caa182117b2b7b820550cc20dff8be2c0f0.tar.gz
volse-hubzilla-a41c7caa182117b2b7b820550cc20dff8be2c0f0.tar.bz2
volse-hubzilla-a41c7caa182117b2b7b820550cc20dff8be2c0f0.zip
Merge branch 'security-fixes-lfi-xss-open-redirect' into 'dev'
Security fixes See merge request hubzilla/core!2017
-rw-r--r--Zotlabs/Module/Settings/Calendar.php10
-rw-r--r--Zotlabs/Module/Settings/Channel_home.php10
-rw-r--r--Zotlabs/Module/Settings/Connections.php10
-rw-r--r--Zotlabs/Module/Settings/Directory.php10
-rw-r--r--Zotlabs/Module/Settings/Editor.php10
-rw-r--r--Zotlabs/Module/Settings/Events.php10
-rw-r--r--Zotlabs/Module/Settings/Manage.php10
-rw-r--r--Zotlabs/Module/Settings/Network.php8
-rw-r--r--Zotlabs/Module/Settings/Photos.php12
-rw-r--r--Zotlabs/Module/Settings/Profiles.php4
-rw-r--r--include/network.php8
-rw-r--r--include/text.php12
-rw-r--r--tests/unit/AntiXSSTest.php20
-rw-r--r--tests/unit/includes/NetworkTest.php33
-rw-r--r--view/theme/redbasic/php/style.php5
15 files changed, 122 insertions, 50 deletions
diff --git a/Zotlabs/Module/Settings/Calendar.php b/Zotlabs/Module/Settings/Calendar.php
index ab85eb450..65240c635 100644
--- a/Zotlabs/Module/Settings/Calendar.php
+++ b/Zotlabs/Module/Settings/Calendar.php
@@ -11,14 +11,14 @@ class Calendar {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Calendar {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Calendar Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Channel_home.php b/Zotlabs/Module/Settings/Channel_home.php
index e8faa7fb2..470dbe4c3 100644
--- a/Zotlabs/Module/Settings/Channel_home.php
+++ b/Zotlabs/Module/Settings/Channel_home.php
@@ -13,7 +13,7 @@ class Channel_home {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
@@ -25,10 +25,10 @@ class Channel_home {
$channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : '');
set_pconfig(local_channel(),'system','channel_menu',$channel_menu);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -82,7 +82,7 @@ class Channel_home {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Channel Home Settings'),
@@ -90,7 +90,7 @@ class Channel_home {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Connections.php b/Zotlabs/Module/Settings/Connections.php
index 4369deb27..52a95a3d1 100644
--- a/Zotlabs/Module/Settings/Connections.php
+++ b/Zotlabs/Module/Settings/Connections.php
@@ -11,14 +11,14 @@ class Connections {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Connections {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Connections Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Directory.php b/Zotlabs/Module/Settings/Directory.php
index d1dd0677e..09ea61f60 100644
--- a/Zotlabs/Module/Settings/Directory.php
+++ b/Zotlabs/Module/Settings/Directory.php
@@ -11,14 +11,14 @@ class Directory {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Directory {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Directory Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Editor.php b/Zotlabs/Module/Settings/Editor.php
index cf6dd2807..85c3e69ae 100644
--- a/Zotlabs/Module/Settings/Editor.php
+++ b/Zotlabs/Module/Settings/Editor.php
@@ -11,14 +11,14 @@ class Editor {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Editor {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Editor Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Events.php b/Zotlabs/Module/Settings/Events.php
index ab393c932..0a0e3516c 100644
--- a/Zotlabs/Module/Settings/Events.php
+++ b/Zotlabs/Module/Settings/Events.php
@@ -11,14 +11,14 @@ class Events {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Events {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Events Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Manage.php b/Zotlabs/Module/Settings/Manage.php
index cbc494cf8..6fb57eafb 100644
--- a/Zotlabs/Module/Settings/Manage.php
+++ b/Zotlabs/Module/Settings/Manage.php
@@ -12,14 +12,14 @@ class Manage {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -35,14 +35,14 @@ class Manage {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Channel Manager Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Network.php b/Zotlabs/Module/Settings/Network.php
index 9f5bdb2e5..eae963a25 100644
--- a/Zotlabs/Module/Settings/Network.php
+++ b/Zotlabs/Module/Settings/Network.php
@@ -21,10 +21,10 @@ class Network {
$network_divmore_height = 50;
set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -53,7 +53,7 @@ class Network {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Stream Settings'),
@@ -61,7 +61,7 @@ class Network {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Photos.php b/Zotlabs/Module/Settings/Photos.php
index 8195d660b..f68c8847b 100644
--- a/Zotlabs/Module/Settings/Photos.php
+++ b/Zotlabs/Module/Settings/Photos.php
@@ -7,18 +7,18 @@ use Zotlabs\Lib\Libsync;
class Photos {
function post() {
-
+
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
-
+
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
-
+
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Photos {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Photos Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
-
+
return $o;
}
diff --git a/Zotlabs/Module/Settings/Profiles.php b/Zotlabs/Module/Settings/Profiles.php
index a1a1b8d96..0ff2dfb6d 100644
--- a/Zotlabs/Module/Settings/Profiles.php
+++ b/Zotlabs/Module/Settings/Profiles.php
@@ -23,7 +23,7 @@ class Profiles {
Libsync::build_sync_packet();
- if($_POST['rpath'])
+ if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -43,7 +43,7 @@ class Profiles {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
- '$rpath' => $rpath,
+ '$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Profiles Settings'),
diff --git a/include/network.php b/include/network.php
index fa408e602..a236a6f8e 100644
--- a/include/network.php
+++ b/include/network.php
@@ -559,6 +559,14 @@ function z_dns_check($h,$check_mx = 0) {
return((@dns_get_record($h,$opts) || filter_var($h, FILTER_VALIDATE_IP)) ? true : false);
}
+function is_local_url($url) {
+ if (str_starts_with($url, z_root()) || str_starts_with($url, '/')) {
+ return true;
+ }
+
+ return false;
+}
+
/**
* @brief Validates a given URL.
*
diff --git a/include/text.php b/include/text.php
index 9a2ca1af4..0c806d009 100644
--- a/include/text.php
+++ b/include/text.php
@@ -114,6 +114,18 @@ function escape_tags($string) {
return (htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false));
}
+/**
+ * Escape URL's so they're safe for use in HTML and in HTML element attributes.
+ */
+function escape_url($input) {
+ if (empty($input)) {
+ return EMPTY_STR;
+ }
+
+ // This is a bit crude but seems to do the trick for now. It makes no
+ // guarantees that the URL is valid for use after escaping.
+ return htmlspecialchars($input, ENT_HTML5 | ENT_QUOTES);
+}
function z_input_filter($s,$type = 'text/bbcode',$allow_code = false) {
diff --git a/tests/unit/AntiXSSTest.php b/tests/unit/AntiXSSTest.php
index b45042a1e..09642726f 100644
--- a/tests/unit/AntiXSSTest.php
+++ b/tests/unit/AntiXSSTest.php
@@ -24,6 +24,26 @@ class AntiXSSTest extends TestCase {
$this->assertEquals("&lt;submit type=&quot;button&quot; onclick=&quot;alert('failed!');&quot; /&gt;", $escapedString);
}
+ /**
+ * @dataProvider urlTestProvider
+ */
+ public function testEscapeURL($url, $expected) : void {
+ $this->assertEquals($expected, escape_url($url));
+ }
+
+ public function urlTestProvider() : array {
+ return [
+ [
+ "https://example.com/settings/calendar/?f=&rpath=https://example.com/cdav/calendar'><script>alert('boom')</script>",
+ "https://example.com/settings/calendar/?f=&amp;rpath=https://example.com/cdav/calendar&apos;&gt;&lt;script&gt;alert(&apos;boom&apos;)&lt;/script&gt;"
+ ],
+ [
+ "settings/calendar/?f=&rpath=https://example.com'+accesskey=x+onclick=alert(/boom/);a='",
+ "settings/calendar/?f=&amp;rpath=https://example.com&apos;+accesskey=x+onclick=alert(/boom/);a=&apos;"
+ ],
+ ];
+ }
+
/**
*xmlify and unxmlify
*/
diff --git a/tests/unit/includes/NetworkTest.php b/tests/unit/includes/NetworkTest.php
new file mode 100644
index 000000000..0b9b42e00
--- /dev/null
+++ b/tests/unit/includes/NetworkTest.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * tests function from include/network.php
+ *
+ * @package test.util
+ */
+
+use PHPUnit\Framework\TestCase;
+
+require_once('include/network.php');
+
+class NetworkTest extends TestCase {
+
+ public function setup() : void {
+ \App::set_baseurl("https://mytest.org");
+ }
+
+ /**
+ * @dataProvider localUrlTestProvider
+ */
+ public function testIsLocalURL($url, $expected) {
+ $this->assertEquals($expected, is_local_url($url));
+ }
+
+ public function localUrlTestProvider() : array {
+ return [
+ [ '/some/path', true ],
+ [ 'https://mytest.org/some/path', true ],
+ [ 'https://other.site/some/path', false ],
+ ];
+ }
+}
+
diff --git a/view/theme/redbasic/php/style.php b/view/theme/redbasic/php/style.php
index 6ff281581..3dbc29a96 100644
--- a/view/theme/redbasic/php/style.php
+++ b/view/theme/redbasic/php/style.php
@@ -36,9 +36,8 @@ if(! App::$install) {
// not --- like the mobile theme does instead.
// Allow layouts to over-ride the schema
-
-if($_REQUEST['schema']) {
- $schema = $_REQUEST['schema'];
+if (isset($_REQUEST['schema']) && preg_match('/^[\w_-]+$/i', $_REQUEST['schema'])) {
+ $schema = $_REQUEST['schema'];
}
if (($schema) && ($schema != '---')) {