mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
fix($parse): disallow access to window and dom in expressions
This commit is contained in:
parent
4b71bbc988
commit
be0b485669
4 changed files with 169 additions and 81 deletions
16
docs/content/error/parse/isecdom.ngdoc
Normal file
16
docs/content/error/parse/isecdom.ngdoc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
@ngdoc error
|
||||
@name $parse:isecdom
|
||||
@fullName Referencing a DOM node in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access a DOM node.
|
||||
|
||||
AngularJS restricts access to DOM nodes from within expressions since it's a known way to
|
||||
execute arbitrary Javascript code.
|
||||
|
||||
This check is only performed on object index and function calls in Angular expressions. These are
|
||||
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
|
||||
perform this check - it's up to the developer to not expose such sensitive and powerful objects
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid access to DOM nodes.
|
||||
16
docs/content/error/parse/isecwindow.ngdoc
Normal file
16
docs/content/error/parse/isecwindow.ngdoc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
@ngdoc error
|
||||
@name $parse:isecwindow
|
||||
@fullName Referencing Window object in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access a Window object.
|
||||
|
||||
AngularJS restricts access to the Window object from within expressions since it's a known way to
|
||||
execute arbitrary Javascript code.
|
||||
|
||||
This check is only performed on object index and function calls in Angular expressions. These are
|
||||
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
|
||||
perform this check - it's up to the developer to not expose such sensitive and powerful objects
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid Window access.
|
||||
|
|
@ -42,12 +42,20 @@ function ensureSafeObject(obj, fullExpression) {
|
|||
if (obj && obj.constructor === obj) {
|
||||
throw $parseMinErr('isecfn',
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}', fullExpression);
|
||||
//
|
||||
} else if (// isWindow(obj)
|
||||
obj && obj.document && obj.location && obj.alert && obj.setInterval) {
|
||||
throw $parseMinErr('isecwindow',
|
||||
'Referencing the Window in Angular expressions is disallowed! Expression: {0}', fullExpression);
|
||||
} else if (// isElement(obj)
|
||||
obj && (obj.nodeName || (obj.on && obj.find))) {
|
||||
throw $parseMinErr('isecdom',
|
||||
'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', fullExpression);
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var OPERATORS = {
|
||||
'null':function(){return null;},
|
||||
'true':function(){return true;},
|
||||
|
|
@ -688,6 +696,9 @@ function parser(text, json, $filter, csp){
|
|||
args.push(argsFn[i](scope, locals));
|
||||
}
|
||||
var fnPtr = fn(scope, locals, context) || noop;
|
||||
|
||||
ensureSafeObject(fnPtr, text);
|
||||
|
||||
// IE stupidity!
|
||||
var v = fnPtr.apply
|
||||
? fnPtr.apply(context, args)
|
||||
|
|
@ -703,7 +714,7 @@ function parser(text, json, $filter, csp){
|
|||
v = v.$$v;
|
||||
}
|
||||
|
||||
return v;
|
||||
return ensureSafeObject(v, text);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -555,100 +555,145 @@ describe('parser', function() {
|
|||
});
|
||||
|
||||
describe('sandboxing', function() {
|
||||
it('should NOT allow access to Function constructor in getter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor');
|
||||
describe('Function constructor', function() {
|
||||
it('should NOT allow access to Function constructor in getter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor("alert(1)")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor("alert(1)")');
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor("alert(1)")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor("alert(1)")');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('[].toString.constructor.foo');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: [].toString.constructor.foo');
|
||||
expect(function() {
|
||||
scope.$eval('[].toString.constructor.foo');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: [].toString.constructor.foo');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]');
|
||||
expect(function() {
|
||||
scope.$eval('{}["toString"]["constructor"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}["toString"]["constructor"]');
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]');
|
||||
expect(function() {
|
||||
scope.$eval('{}["toString"]["constructor"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}["toString"]["constructor"]');
|
||||
|
||||
scope.a = [];
|
||||
expect(function() {
|
||||
scope.$eval('a.toString.constructor', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString.constructor');
|
||||
expect(function() {
|
||||
scope.$eval('a.toString["constructor"]', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString["constructor"]');
|
||||
});
|
||||
scope.a = [];
|
||||
expect(function() {
|
||||
scope.$eval('a.toString.constructor', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString.constructor');
|
||||
expect(function() {
|
||||
scope.$eval('a.toString["constructor"]', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString["constructor"]');
|
||||
});
|
||||
|
||||
it('should NOT allow access to Function constructor in setter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor = 1');
|
||||
it('should NOT allow access to Function constructor in setter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor = 1');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor.a = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor.a = 1');
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor.a = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor.a = 1');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]["constructor"] = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]["constructor"] = 1');
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]["constructor"] = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]["constructor"] = 1');
|
||||
|
||||
|
||||
scope.key1 = "const";
|
||||
scope.key2 = "ructor";
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString[key1 + key2].foo = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString[key1 + key2].foo = 1');
|
||||
scope.key1 = "const";
|
||||
scope.key2 = "ructor";
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString[key1 + key2].foo = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString[key1 + key2].foo = 1');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]["a"] = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]["a"] = 1');
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]["a"] = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString["constructor"]["a"] = 1');
|
||||
|
||||
scope.a = [];
|
||||
expect(function() {
|
||||
scope.$eval('a.toString.constructor = 1', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString.constructor = 1');
|
||||
scope.a = [];
|
||||
expect(function() {
|
||||
scope.$eval('a.toString.constructor = 1', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString.constructor = 1');
|
||||
});
|
||||
|
||||
|
||||
it('should NOT allow access to Function constructor that has been aliased', function() {
|
||||
scope.foo = { "bar": Function };
|
||||
expect(function() {
|
||||
scope.$eval('foo["bar"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: foo["bar"]');
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('should NOT allow access to Function constructor in getter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should NOT allow access to Function constructor that has been aliased', function() {
|
||||
scope.foo = { "bar": Function };
|
||||
expect(function() {
|
||||
scope.$eval('foo["bar"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: foo["bar"]');
|
||||
describe('Window and $element/node', function() {
|
||||
it('should NOT allow access to the Window or DOM when indexing', inject(function($window, $document) {
|
||||
scope.wrap = {w: $window, d: $document};
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('wrap["w"]', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecwindow', 'Referencing the Window in Angular expressions is ' +
|
||||
'disallowed! Expression: wrap["w"]');
|
||||
expect(function() {
|
||||
scope.$eval('wrap["d"]', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecdom', 'Referencing DOM nodes in Angular expressions is ' +
|
||||
'disallowed! Expression: wrap["d"]');
|
||||
}));
|
||||
|
||||
it('should NOT allow access to the Window or DOM returned from a function', inject(function($window, $document) {
|
||||
scope.getWin = valueFn($window);
|
||||
scope.getDoc = valueFn($document);
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('getWin()', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecwindow', 'Referencing the Window in Angular expressions is ' +
|
||||
'disallowed! Expression: getWin()');
|
||||
expect(function() {
|
||||
scope.$eval('getDoc()', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecdom', 'Referencing DOM nodes in Angular expressions is ' +
|
||||
'disallowed! Expression: getDoc()');
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue