prototype: Prevent a potential security issue for cross-site ajax requests.

This commit is contained in:
Tobie Langel 2008-01-23 00:51:25 +00:00
parent dcada47c6d
commit 02cc9992e9
3 changed files with 55 additions and 3 deletions

View File

@ -1,5 +1,7 @@
*SVN*
* Prevent a potential security issue for cross-site ajax requests. [Alexey Feldgendler, sam, Tobie Langel]
* Test for attribute existence before applying more complex CSS3 selectors. Closes #10870. [arty, Tobie Langel]
* Fix "function $A" declaration inside of a conditional (confuses IE). Closes #10882. [Jacco, Andrew Dupont]

View File

@ -189,7 +189,7 @@ Ajax.Request = Class.create(Ajax.Base, {
var contentType = response.getHeader('Content-type');
if (this.options.evalJS == 'force'
|| (this.options.evalJS && contentType
|| (this.options.evalJS && this.isSameOrigin() && contentType
&& contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
this.evalResponse();
}
@ -207,6 +207,15 @@ Ajax.Request = Class.create(Ajax.Base, {
}
},
isSameOrigin: function() {
var m = this.url.match(/^\s*https?:\/\/[^/]*/);
return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
protocol: location.protocol,
domain: document.domain,
port: location.port ? ':' + location.port : ''
}));
},
getHeader: function(name) {
try {
return this.transport.getResponseHeader(name) || null;
@ -282,7 +291,8 @@ Ajax.Response = Class.create({
if (!json) return null;
json = decodeURIComponent(escape(json));
try {
return json.evalJSON(this.request.options.sanitizeJSON);
return json.evalJSON(this.request.options.sanitizeJSON ||
!this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
@ -295,7 +305,8 @@ Ajax.Response = Class.create({
this.responseText.blank())
return null;
try {
return this.responseText.evalJSON(options.sanitizeJSON);
return this.responseText.evalJSON(options.sanitizeJSON ||
!this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}

View File

@ -410,6 +410,45 @@
} else {
info(message);
}
}},
testIsSameOriginMethod: function() {with(this) {
var isSameOrigin = Ajax.Request.prototype.isSameOrigin;
assert(isSameOrigin.call({ url: '/foo/bar.html' }), '/foo/bar.html');
assert(isSameOrigin.call({ url: window.location.toString() }), window.location);
assert(!isSameOrigin.call({ url: 'http://example.com' }), 'http://example.com');
if (isRunningFromRake) {
Ajax.Request.prototype.isSameOrigin = function() {
return false
};
$("content").update('same origin policy');
new Ajax.Request("/response", extendDefault({
parameters: Fixtures.js,
onComplete: function(transport) {
assertEqual("same origin policy", $("content").innerHTML);
}
}));
new Ajax.Request("/response", extendDefault({
parameters: Fixtures.invalidJson,
onException: function(request, error) {
assert(error.message.include('Badly formed JSON string'));
}
}));
new Ajax.Request("/response", extendDefault({
parameters: { 'X-JSON': '{});window.attacked = true;({}' },
onException: function(request, error) {
assert(error.message.include('Badly formed JSON string'));
}
}));
Ajax.Request.prototype.isSameOrigin = isSameOrigin;
} else {
info(message);
}
}}
});
// ]]>