Skip to content
SA-CORE-2018-001.patch 4.89 KiB
Newer Older
diff --git a/includes/common.inc b/includes/common.inc
index 9a28c06..a5c362d 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1499,7 +1499,7 @@ function url($path = NULL, $options = array()) {
   );
 
   if (!isset($options['external'])) {
-    $options['external'] = menu_path_is_external($path);
+    $options['external'] = $_GET['q'] === $path ? FALSE : menu_path_is_external($path);
   }
 
   // May need language dependent rewriting if language.inc is present.
diff --git a/misc/drupal.js b/misc/drupal.js
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -20,6 +20,42 @@
     return jquery_init.call(this, selector, context, rootjQuery);
   };
   jQuery.fn.init.prototype = jquery_init.prototype;
+
+  /**
+   * Pre-filter Ajax requests to guard against XSS attacks.
+   *
+   * See https://github.com/jquery/jquery/issues/2432
+   */
+  if ($.ajaxPrefilter) {
+    // For newer versions of jQuery, use an Ajax prefilter to prevent
+    // auto-executing script tags from untrusted domains. This is similar to the
+    // fix that is built in to jQuery 3.0 and higher.
+    $.ajaxPrefilter(function (s) {
+      if (s.crossDomain) {
+        s.contents.script = false;
+      }
+    });
+  }
+  else if ($.httpData) {
+    // For the version of jQuery that ships with Drupal core, override
+    // jQuery.httpData to prevent auto-detecting "script" data types from
+    // untrusted domains.
+    var jquery_httpData = $.httpData;
+    $.httpData = function (xhr, type, s) {
+      // @todo Consider backporting code from newer jQuery versions to check for
+      //   a cross-domain request here, rather than using Drupal.urlIsLocal() to
+      //   block scripts from all URLs that are not on the same site.
+      if (!type && (!s || !Drupal.urlIsLocal(s.url))) {
+        var content_type = xhr.getResponseHeader('content-type') || '';
+        if (content_type.indexOf('javascript') >= 0) {
+          // Default to a safe data type.
+          type = 'text';
+        }
+      }
+      return jquery_httpData.call(this, xhr, type, s);
+    };
+    $.httpData.prototype = jquery_httpData.prototype;
+  }
 })();
 
 var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} };
@@ -71,7 +107,7 @@ Drupal.attachBehaviors = function(context) {
  */
 Drupal.checkPlain = function(str) {
   str = String(str);
-  var replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
+  var replace = { '&': '&amp;', "'": '&#39;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
   for (var character in replace) {
     var regex = new RegExp(character, 'g');
     str = str.replace(regex, replace[character]);
@@ -177,6 +213,72 @@ Drupal.formatPlural = function(count, singular, plural, args) {
 };
 
 /**
+ * Returns the passed in URL as an absolute URL.
+ *
+ * @param url
+ *   The URL string to be normalized to an absolute URL.
+ *
+ * @return
+ *   The normalized, absolute URL.
+ *
+ * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
+ * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
+ * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
+ */
+Drupal.absoluteUrl = function (url) {
+  var urlParsingNode = document.createElement('a');
+
+  // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
+  // strings may throw an exception.
+  try {
+    url = decodeURIComponent(url);
+  } catch (e) {}
+
+  urlParsingNode.setAttribute('href', url);
+
+  // IE <= 7 normalizes the URL when assigned to the anchor node similar to
+  // the other browsers.
+  return urlParsingNode.cloneNode(false).href;
+};
+
+/**
+ * Returns true if the URL is within Drupal's base path.
+ *
+ * @param url
+ *   The URL string to be tested.
+ *
+ * @return
+ *   Boolean true if local.
+ *
+ * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
+ */
+Drupal.urlIsLocal = function (url) {
+  // Always use browser-derived absolute URLs in the comparison, to avoid
+  // attempts to break out of the base path using directory traversal.
+  var absoluteUrl = Drupal.absoluteUrl(url);
+  var protocol = location.protocol;
+
+  // Consider URLs that match this site's base URL but use HTTPS instead of HTTP
+  // as local as well.
+  if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
+    protocol = 'https:';
+  }
+  var baseUrl = protocol + '//' + location.host + Drupal.settings.basePath.slice(0, -1);
+
+  // Decoding non-UTF-8 strings may throw an exception.
+  try {
+    absoluteUrl = decodeURIComponent(absoluteUrl);
+  } catch (e) {}
+  try {
+    baseUrl = decodeURIComponent(baseUrl);
+  } catch (e) {}
+
+  // The given URL matches the site's base URL, or has a path under the site's
+  // base URL.
+  return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0;
+};
+
+/**
  * Generate the themed representation of a Drupal object.
  *
  * All requests for themed output must go through this function. It examines