diff options
| author | Chirayu Krishnappa | 2013-08-09 14:47:13 -0700 |
|---|---|---|
| committer | Chirayu Krishnappa | 2013-09-17 18:15:49 -0700 |
| commit | be0b4856699334ff51bacf2d1fd3394663d6bd28 (patch) | |
| tree | 19dc768b7d6b5f79c612a5d71f598f7e5cfab39e | |
| parent | 4b71bbc9886f6cf8e939d257c755bf7c4a94396e (diff) | |
| download | angular.js-be0b4856699334ff51bacf2d1fd3394663d6bd28.tar.bz2 | |
fix($parse): disallow access to window and dom in expressions
| -rw-r--r-- | docs/content/error/parse/isecdom.ngdoc | 16 | ||||
| -rw-r--r-- | docs/content/error/parse/isecwindow.ngdoc | 16 | ||||
| -rw-r--r-- | src/ng/parse.js | 15 | ||||
| -rw-r--r-- | test/ng/parseSpec.js | 215 |
4 files changed, 175 insertions, 87 deletions
diff --git a/docs/content/error/parse/isecdom.ngdoc b/docs/content/error/parse/isecdom.ngdoc new file mode 100644 index 00000000..666bf36c --- /dev/null +++ b/docs/content/error/parse/isecdom.ngdoc @@ -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. diff --git a/docs/content/error/parse/isecwindow.ngdoc b/docs/content/error/parse/isecwindow.ngdoc new file mode 100644 index 00000000..81adeea0 --- /dev/null +++ b/docs/content/error/parse/isecwindow.ngdoc @@ -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. diff --git a/src/ng/parse.js b/src/ng/parse.js index 5597acd8..8f8c0f87 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -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); }; } diff --git a/test/ng/parseSpec.js b/test/ng/parseSpec.js index a82f736f..44b648c5 100644 --- a/test/ng/parseSpec.js +++ b/test/ng/parseSpec.js @@ -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'); - - 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"]'); - }).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"]'); - }); - - 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'); + 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.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"]'); + + 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"]'); + }); - expect(function() { - scope.$eval('{}.toString.constructor.a = 1'); - }).toThrowMinErr( - '$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' + - 'Expression: {}.toString.constructor.a = 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"]["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'); + + 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'); + }); - expect(function() { - scope.$eval('{}.toString["constructor"]["constructor"] = 1'); - }).toThrowMinErr( - '$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' + - 'Expression: {}.toString["constructor"]["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"]'); - 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'); - 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 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()'); + })); }); }); |
