Merge branch 'MDL-69050-master-allowlist' of git://github.com/mudrd8mz/moodle into master
This commit is contained in:
@@ -733,7 +733,7 @@ $cache = '.var_export($cache, true).';
|
||||
/**
|
||||
* List all core subsystems and their location
|
||||
*
|
||||
* This is a whitelist of components that are part of the core and their
|
||||
* This is a list of components that are part of the core and their
|
||||
* language strings are defined in /lang/en/<<subsystem>>.php. If a given
|
||||
* plugin is not listed here and it does not have proper plugintype prefix,
|
||||
* then it is considered as course activity module.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains a class providing functions used to check the host/port black/whitelists for curl.
|
||||
* Contains a class providing functions used to check the allowed/blocked host/ports for curl.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2016 Jake Dallimore
|
||||
@@ -32,7 +32,7 @@ defined('MOODLE_INTERNAL') || exit();
|
||||
* Host and port checking for curl.
|
||||
*
|
||||
* This class provides a means to check URL/host/port against the system-level cURL security entries.
|
||||
* It does not provide a means to add URLs, hosts or ports to the black/white lists; this is configured manually
|
||||
* It does not provide a means to add URLs, hosts or ports to the allowed/blocked lists; this is configured manually
|
||||
* via the site admin section of Moodle (See: 'Site admin' > 'Security' > 'HTTP Security').
|
||||
*
|
||||
* This class is currently used by the 'curl' wrapper class in lib/filelib.php.
|
||||
@@ -55,12 +55,12 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks whether the given URL is blacklisted by checking its address and port number against the black/white lists.
|
||||
* Checks whether the given URL is blocked by checking its address and port number against the allow/block lists.
|
||||
* The behaviour of this function can be classified as strict, as it returns true for URLs which are invalid or
|
||||
* could not be parsed, as well as those valid URLs which were found in the blacklist.
|
||||
* could not be parsed, as well as those valid URLs which were found in the blocklist.
|
||||
*
|
||||
* @param string $urlstring the URL to check.
|
||||
* @return bool true if the URL is blacklisted or invalid and false if the URL is not blacklisted.
|
||||
* @return bool true if the URL is blocked or invalid and false if the URL is not blocked.
|
||||
*/
|
||||
public function url_is_blocked($urlstring) {
|
||||
// If no config data is present, then all hosts/ports are allowed.
|
||||
@@ -85,7 +85,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
if ($parsed['port'] && $parsed['host']) {
|
||||
// Check the host and port against the blacklist/whitelist entries.
|
||||
// Check the host and port against the allow/block entries.
|
||||
return $this->host_is_blocked($parsed['host']) || $this->port_is_blocked($parsed['port']);
|
||||
}
|
||||
return true;
|
||||
@@ -114,9 +114,9 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
* - This will perform a DNS reverse lookup if required.
|
||||
*
|
||||
* The behaviour of this function can be classified as strict, as it returns true for hosts which are invalid or
|
||||
* could not be parsed, as well as those valid URLs which were found in the blacklist.
|
||||
* could not be parsed, as well as those valid URLs which were found in the blocklist.
|
||||
*
|
||||
* @param string $host the host component of the URL to check against the blacklist.
|
||||
* @param string $host the host component of the URL to check against the blocklist.
|
||||
* @return bool true if the host is both valid and blocked, false otherwise.
|
||||
*/
|
||||
protected function host_is_blocked($host) {
|
||||
@@ -126,7 +126,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
|
||||
// Fix for square brackets in the 'host' portion of the URL (only occurs if an IPv6 address is specified).
|
||||
$host = str_replace(array('[', ']'), '', $host); // RFC3986, section 3.2.2.
|
||||
$blacklistedhosts = $this->get_blacklisted_hosts_by_category();
|
||||
$blockedhosts = $this->get_blocked_hosts_by_category();
|
||||
|
||||
if (ip_utils::is_ip_address($host)) {
|
||||
if ($this->address_explicitly_blocked($host)) {
|
||||
@@ -134,7 +134,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
// Only perform a reverse lookup if there is a point to it (i.e. we have rules to check against).
|
||||
if ($blacklistedhosts['domain'] || $blacklistedhosts['domainwildcard']) {
|
||||
if ($blockedhosts['domain'] || $blockedhosts['domainwildcard']) {
|
||||
// DNS reverse lookup - supports both IPv4 and IPv6 address formats.
|
||||
$hostname = gethostbyaddr($host);
|
||||
if ($hostname !== $host && $this->host_explicitly_blocked($hostname)) {
|
||||
@@ -147,7 +147,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
// Only perform a forward lookup if there are IP rules to check against.
|
||||
if ($blacklistedhosts['ipv4'] || $blacklistedhosts['ipv6']) {
|
||||
if ($blockedhosts['ipv4'] || $blockedhosts['ipv6']) {
|
||||
// DNS forward lookup - returns a list of only IPv4 addresses!
|
||||
$hostips = $this->get_host_list_by_name($host);
|
||||
|
||||
@@ -156,7 +156,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If any of the returned IPs are in the blacklist, block the request.
|
||||
// If any of the returned IPs are in the blocklist, block the request.
|
||||
foreach ($hostips as $hostip) {
|
||||
if ($this->address_explicitly_blocked($hostip)) {
|
||||
return true;
|
||||
@@ -182,10 +182,10 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given port is blocked, as determined by its absence on the ports whitelist.
|
||||
* Ports are assumed to be blocked unless found in the whitelist.
|
||||
* Checks whether the given port is blocked, as determined by its absence on the ports allowlist.
|
||||
* Ports are assumed to be blocked unless found in the allowlist.
|
||||
*
|
||||
* @param integer|string $port the port to check against the ports whitelist.
|
||||
* @param integer|string $port the port to check against the ports allowlist.
|
||||
* @return bool true if the port is blocked, false otherwise.
|
||||
*/
|
||||
protected function port_is_blocked($port) {
|
||||
@@ -194,28 +194,28 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
if (empty($port) || (string)$portnum !== (string)$port || $port < 0) {
|
||||
return true;
|
||||
}
|
||||
$allowedports = $this->get_whitelisted_ports();
|
||||
$allowedports = $this->get_allowed_ports();
|
||||
return !empty($allowedports) && !in_array($portnum, $allowedports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to check whether we have any entries in the host blacklist or ports whitelist admin settings.
|
||||
* If no entries are found at all, the assumption is that the blacklist is disabled entirely.
|
||||
* Convenience method to check whether we have any entries in the host blocklist or ports allowlist admin settings.
|
||||
* If no entries are found at all, the assumption is that the blocklist is disabled entirely.
|
||||
*
|
||||
* @return bool true if one or more entries exist, false otherwise.
|
||||
*/
|
||||
public function is_enabled() {
|
||||
return (!empty($this->get_whitelisted_ports()) || !empty($this->get_blacklisted_hosts()));
|
||||
return (!empty($this->get_allowed_ports()) || !empty($this->get_blocked_hosts()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the input address is blocked by at any of the IPv4 or IPv6 address rules.
|
||||
*
|
||||
* @param string $addr the ip address to check.
|
||||
* @return bool true if the address is covered by an entry in the blacklist, false otherwise.
|
||||
* @return bool true if the address is covered by an entry in the blocklist, false otherwise.
|
||||
*/
|
||||
protected function address_explicitly_blocked($addr) {
|
||||
$blockedhosts = $this->get_blacklisted_hosts_by_category();
|
||||
$blockedhosts = $this->get_blocked_hosts_by_category();
|
||||
$iphostsblocked = array_merge($blockedhosts['ipv4'], $blockedhosts['ipv6']);
|
||||
return address_in_subnet($addr, implode(',', $iphostsblocked));
|
||||
}
|
||||
@@ -224,10 +224,10 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
* Checks whether the input hostname is blocked by any of the domain/wildcard rules.
|
||||
*
|
||||
* @param string $host the hostname to check
|
||||
* @return bool true if the host is covered by an entry in the blacklist, false otherwise.
|
||||
* @return bool true if the host is covered by an entry in the blocklist, false otherwise.
|
||||
*/
|
||||
protected function host_explicitly_blocked($host) {
|
||||
$blockedhosts = $this->get_blacklisted_hosts_by_category();
|
||||
$blockedhosts = $this->get_blocked_hosts_by_category();
|
||||
$domainhostsblocked = array_merge($blockedhosts['domain'], $blockedhosts['domainwildcard']);
|
||||
return ip_utils::is_domain_in_allowed_list($host, $domainhostsblocked);
|
||||
}
|
||||
@@ -238,10 +238,10 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
*
|
||||
* @return array of host/domain/ip entries from the 'curlsecurityblockedhosts' config.
|
||||
*/
|
||||
protected function get_blacklisted_hosts_by_category() {
|
||||
protected function get_blocked_hosts_by_category() {
|
||||
// For each of the admin setting entries, check and place in the correct section of the config array.
|
||||
$config = ['ipv6' => [], 'ipv4' => [], 'domain' => [], 'domainwildcard' => []];
|
||||
$entries = $this->get_blacklisted_hosts();
|
||||
$entries = $this->get_blocked_hosts();
|
||||
foreach ($entries as $entry) {
|
||||
if (ip_utils::is_ipv6_address($entry) || ip_utils::is_ipv6_range($entry)) {
|
||||
$config['ipv6'][] = $entry;
|
||||
@@ -257,11 +257,11 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that returns the whitelisted ports, as defined in the 'curlsecurityallowedport' setting.
|
||||
* Helper that returns the allowed ports, as defined in the 'curlsecurityallowedport' setting.
|
||||
*
|
||||
* @return array the array of whitelisted ports.
|
||||
* @return array the array of allowed ports.
|
||||
*/
|
||||
protected function get_whitelisted_ports() {
|
||||
protected function get_allowed_ports() {
|
||||
global $CFG;
|
||||
if (!isset($CFG->curlsecurityallowedport)) {
|
||||
return [];
|
||||
@@ -272,11 +272,11 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that returns the blacklisted hosts, as defined in the 'curlsecurityblockedhosts' setting.
|
||||
* Helper that returns the blocked hosts, as defined in the 'curlsecurityblockedhosts' setting.
|
||||
*
|
||||
* @return array the array of blacklisted host entries.
|
||||
* @return array the array of blocked host entries.
|
||||
*/
|
||||
protected function get_blacklisted_hosts() {
|
||||
protected function get_blocked_hosts() {
|
||||
global $CFG;
|
||||
if (!isset($CFG->curlsecurityblockedhosts)) {
|
||||
return [];
|
||||
|
||||
@@ -38,7 +38,7 @@ class mustache_engine extends \Mustache_Engine {
|
||||
/**
|
||||
* @var string[] Names of helpers that aren't allowed to be called within other helpers.
|
||||
*/
|
||||
private $blacklistednestedhelpers = [];
|
||||
private $disallowednestedhelpers = [];
|
||||
|
||||
/**
|
||||
* Mustache engine constructor.
|
||||
@@ -47,13 +47,19 @@ class mustache_engine extends \Mustache_Engine {
|
||||
* $options = [
|
||||
* // A list of helpers (by name) to prevent from executing within the rendering
|
||||
* // of other helpers.
|
||||
* 'blacklistednestedhelpers' => ['js']
|
||||
* 'disallowednestedhelpers' => ['js']
|
||||
* ];
|
||||
* @param array $options [description]
|
||||
*/
|
||||
public function __construct(array $options = []) {
|
||||
|
||||
if (isset($options['blacklistednestedhelpers'])) {
|
||||
$this->blacklistednestedhelpers = $options['blacklistednestedhelpers'];
|
||||
debugging('blacklistednestedhelpers option is deprecated. Use disallowednestedhelpers instead.', DEBUG_DEVELOPER);
|
||||
$this->disallowednestedhelpers = $options['blacklistednestedhelpers'];
|
||||
}
|
||||
|
||||
if (isset($options['disallowednestedhelpers'])) {
|
||||
$this->disallowednestedhelpers = $options['disallowednestedhelpers'];
|
||||
}
|
||||
|
||||
parent::__construct($options);
|
||||
@@ -69,7 +75,7 @@ class mustache_engine extends \Mustache_Engine {
|
||||
public function getHelpers()
|
||||
{
|
||||
if (!isset($this->helpers)) {
|
||||
$this->helpers = new mustache_helper_collection(null, $this->blacklistednestedhelpers);
|
||||
$this->helpers = new mustache_helper_collection(null, $this->disallowednestedhelpers);
|
||||
}
|
||||
|
||||
return $this->helpers;
|
||||
|
||||
@@ -34,7 +34,7 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
/**
|
||||
* @var string[] Names of helpers that aren't allowed to be called within other helpers.
|
||||
*/
|
||||
private $blacklistednestedhelpers = [];
|
||||
private $disallowednestedhelpers = [];
|
||||
|
||||
/**
|
||||
* Helper Collection constructor.
|
||||
@@ -44,43 +44,43 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
* @throws \Mustache_Exception_InvalidArgumentException if the $helpers argument isn't an array or Traversable
|
||||
*
|
||||
* @param array|\Traversable $helpers (default: null)
|
||||
* @param string[] $blacklistednestedhelpers Names of helpers that aren't allowed to be called within other helpers.
|
||||
* @param string[] $disallowednestedhelpers Names of helpers that aren't allowed to be called within other helpers.
|
||||
*/
|
||||
public function __construct($helpers = null, array $blacklistednestedhelpers = []) {
|
||||
$this->blacklistednestedhelpers = $blacklistednestedhelpers;
|
||||
public function __construct($helpers = null, array $disallowednestedhelpers = []) {
|
||||
$this->disallowednestedhelpers = $disallowednestedhelpers;
|
||||
parent::__construct($helpers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a helper to this collection.
|
||||
*
|
||||
* This function has overridden the parent implementation to provide blacklist
|
||||
* This function has overridden the parent implementation to provide disallowing
|
||||
* functionality for certain helpers to prevent them being called from within
|
||||
* other helpers. This is because the JavaScript helper can be used in a
|
||||
* security exploit if it can be nested.
|
||||
*
|
||||
* The function will wrap callable helpers in an anonymous function that strips
|
||||
* out the blacklisted helpers from the source string before giving it to the
|
||||
* helper function. This prevents the blacklisted helper functions from being
|
||||
* out the disallowed helpers from the source string before giving it to the
|
||||
* helper function. This prevents the disallowed helper functions from being
|
||||
* called by nested render functions from within other helpers.
|
||||
*
|
||||
* @see \Mustache_HelperCollection::add()
|
||||
* @param string $name
|
||||
* @param mixed $helper
|
||||
*/
|
||||
public function add($name, $helper)
|
||||
{
|
||||
$blacklist = $this->blacklistednestedhelpers;
|
||||
public function add($name, $helper) {
|
||||
|
||||
if (is_callable($helper) && !empty($blacklist)) {
|
||||
$helper = function($source, \Mustache_LambdaHelper $lambdahelper) use ($helper, $blacklist) {
|
||||
$disallowedlist = $this->disallowednestedhelpers;
|
||||
|
||||
// Temporarily override the blacklisted helpers to return nothing
|
||||
if (is_callable($helper) && !empty($disallowedlist)) {
|
||||
$helper = function($source, \Mustache_LambdaHelper $lambdahelper) use ($helper, $disallowedlist) {
|
||||
|
||||
// Temporarily override the disallowed helpers to return nothing
|
||||
// so that they can't be executed from within other helpers.
|
||||
$disabledhelpers = $this->disable_helpers($blacklist);
|
||||
$disabledhelpers = $this->disable_helpers($disallowedlist);
|
||||
// Call the original function with the modified sources.
|
||||
$result = call_user_func($helper, $source, $lambdahelper);
|
||||
// Restore the original blacklisted helper implementations now
|
||||
// Restore the original disallowed helper implementations now
|
||||
// that this helper has finished executing so that the rest of
|
||||
// the rendering process continues to work correctly.
|
||||
$this->restore_helpers($disabledhelpers);
|
||||
@@ -89,7 +89,7 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
// This is done because a secondary render is called on the result
|
||||
// of a helper function if it still includes mustache tags. See
|
||||
// the section function of Mustache_Compiler for details.
|
||||
return $this->strip_blacklisted_helpers($blacklist, $result);
|
||||
return $this->strip_disallowed_helpers($disallowedlist, $result);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -137,18 +137,18 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given string and remove any reference to blacklisted helpers.
|
||||
* Parse the given string and remove any reference to disallowed helpers.
|
||||
*
|
||||
* E.g.
|
||||
* $blacklist = ['js'];
|
||||
* $disallowedlist = ['js'];
|
||||
* $string = "core, move, {{#js}} some nasty JS hack {{/js}}"
|
||||
* result: "core, move, {{}}"
|
||||
*
|
||||
* @param string[] $blacklist List of helper names to strip
|
||||
* @param string[] $disallowedlist List of helper names to strip
|
||||
* @param string $string String to parse
|
||||
* @return string Parsed string
|
||||
*/
|
||||
public function strip_blacklisted_helpers($blacklist, $string) {
|
||||
public function strip_disallowed_helpers($disallowedlist, $string) {
|
||||
$starttoken = \Mustache_Tokenizer::T_SECTION;
|
||||
$endtoken = \Mustache_Tokenizer::T_END_SECTION;
|
||||
if ($endtoken == '/') {
|
||||
@@ -160,7 +160,7 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
// the user is able to change the delimeters on a per template
|
||||
// basis so they may not be curly braces.
|
||||
return '/\s*' . $starttoken . '\s*'. $name . '\W+.*' . $endtoken . '\s*' . $name . '\s*/';
|
||||
}, $blacklist);
|
||||
}, $disallowedlist);
|
||||
|
||||
// This will strip out unwanted helpers from the $source string
|
||||
// before providing it to the original helper function.
|
||||
@@ -168,9 +168,25 @@ class mustache_helper_collection extends \Mustache_HelperCollection {
|
||||
// Before:
|
||||
// "core, move, {{#js}} some nasty JS hack {{/js}}"
|
||||
// After:
|
||||
// "core, move, {{}}"
|
||||
// "core, move, {{}}".
|
||||
return preg_replace_callback($regexes, function() {
|
||||
return '';
|
||||
}, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given string and remove any reference to disallowed helpers.
|
||||
*
|
||||
* @deprecated Deprecated since Moodle 3.10 (MDL-69050) - use {@see self::strip_disallowed_helpers()}
|
||||
* @param string[] $disallowedlist List of helper names to strip
|
||||
* @param string $string String to parse
|
||||
* @return string Parsed string
|
||||
*/
|
||||
public function strip_blacklisted_helpers($disallowedlist, $string) {
|
||||
|
||||
debugging('mustache_helper_collection::strip_blacklisted_helpers() is deprecated. ' .
|
||||
'Please use mustache_helper_collection::strip_disallowed_helpers() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
return $this->strip_disallowed_helpers($disallowedlist, $string);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user