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
David Snopek
committed
index a85b8f8..fd68051 100644
--- 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.
David Snopek
committed
+ 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 = { '&': '&', '"': '"', '<': '<', '>': '>' };
+ var replace = { '&': '&', "'": ''', '"': '"', '<': '<', '>': '>' };
for (var character in replace) {
var regex = new RegExp(character, 'g');
str = str.replace(regex, replace[character]);
David Snopek
committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@@ -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