diff options
-rw-r--r-- | includes/common.inc | 5 | ||||
-rw-r--r-- | modules/filter/filter.module | 15 | ||||
-rw-r--r-- | modules/system/system.install | 2 |
3 files changed, 15 insertions, 7 deletions
diff --git a/includes/common.inc b/includes/common.inc index 31474eb5c..b55384e2a 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1142,8 +1142,9 @@ function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) { } // Return an external link if $path contains an allowed absolute URL. - // Only call the slow filter_xss_bad_protocol if $path contains a ':'. - if (strpos($path, ':') !== FALSE && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) { + // Only call the slow filter_xss_bad_protocol if $path contains a ':' before any / ? or #. + $colonpos = strpos($path, ':'); + if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) { // Split off the fragment if (strpos($path, '#') !== FALSE) { list($path, $old_fragment) = explode('#', $path, 2); diff --git a/modules/filter/filter.module b/modules/filter/filter.module index 5ad6da298..d0359c182 100644 --- a/modules/filter/filter.module +++ b/modules/filter/filter.module @@ -1474,19 +1474,26 @@ function filter_xss_bad_protocol($string, $decode = TRUE) { $allowed_protocols = array_flip(variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'))); } - // Get the plain text representation of the attribute value (i.e. its meaning) + // Get the plain text representation of the attribute value (i.e. its meaning). if ($decode) { $string = decode_entities($string); } - // Remove soft hyphen - $string = str_replace(chr(194) . chr(173), '', $string); - // Strip protocols + + // Iteratively remove any invalid protocol found. do { $before = $string; $colonpos = strpos($string, ':'); if ($colonpos > 0) { + // We found a colon, possibly a protocol. Verify. $protocol = substr($string, 0, $colonpos); + // If a colon is preceded by a slash, question mark or hash, it cannot + // possibly be part of the URL scheme. This must be a relative URL, + // which inherits the (safe) protocol of the base document. + if (preg_match('![/?#]!', $protocol)) { + break; + } + // Check if this is a disallowed protocol. if (!isset($allowed_protocols[$protocol])) { $string = substr($string, $colonpos + 1); } diff --git a/modules/system/system.install b/modules/system/system.install index cda02552d..282457bf0 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -3486,7 +3486,7 @@ function system_update_1020() { $ret[] = update_sql("UPDATE {node_revisions} SET body = REPLACE(body, '<break>', '<!--break-->')"); } variable_del('update_1020_ok'); - return $ret; + return $ret; } |