mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-17 03:01:06 +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) {
|
if (obj && obj.constructor === obj) {
|
||||||
throw $parseMinErr('isecfn',
|
throw $parseMinErr('isecfn',
|
||||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}', fullExpression);
|
'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 {
|
} else {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var OPERATORS = {
|
var OPERATORS = {
|
||||||
'null':function(){return null;},
|
'null':function(){return null;},
|
||||||
'true':function(){return true;},
|
'true':function(){return true;},
|
||||||
|
|
@ -688,6 +696,9 @@ function parser(text, json, $filter, csp){
|
||||||
args.push(argsFn[i](scope, locals));
|
args.push(argsFn[i](scope, locals));
|
||||||
}
|
}
|
||||||
var fnPtr = fn(scope, locals, context) || noop;
|
var fnPtr = fn(scope, locals, context) || noop;
|
||||||
|
|
||||||
|
ensureSafeObject(fnPtr, text);
|
||||||
|
|
||||||
// IE stupidity!
|
// IE stupidity!
|
||||||
var v = fnPtr.apply
|
var v = fnPtr.apply
|
||||||
? fnPtr.apply(context, args)
|
? fnPtr.apply(context, args)
|
||||||
|
|
@ -703,7 +714,7 @@ function parser(text, json, $filter, csp){
|
||||||
v = v.$$v;
|
v = v.$$v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return ensureSafeObject(v, text);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -555,100 +555,145 @@ describe('parser', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sandboxing', function() {
|
describe('sandboxing', function() {
|
||||||
it('should NOT allow access to Function constructor in getter', function() {
|
describe('Function constructor', function() {
|
||||||
expect(function() {
|
it('should NOT allow access to Function constructor in getter', function() {
|
||||||
scope.$eval('{}.toString.constructor');
|
expect(function() {
|
||||||
}).toThrowMinErr(
|
scope.$eval('{}.toString.constructor');
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
}).toThrowMinErr(
|
||||||
'Expression: {}.toString.constructor');
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
|
'Expression: {}.toString.constructor');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString.constructor("alert(1)")');
|
scope.$eval('{}.toString.constructor("alert(1)")');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString.constructor("alert(1)")');
|
'Expression: {}.toString.constructor("alert(1)")');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('[].toString.constructor.foo');
|
scope.$eval('[].toString.constructor.foo');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: [].toString.constructor.foo');
|
'Expression: [].toString.constructor.foo');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString["constructor"]');
|
scope.$eval('{}.toString["constructor"]');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString["constructor"]');
|
'Expression: {}.toString["constructor"]');
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}["toString"]["constructor"]');
|
scope.$eval('{}["toString"]["constructor"]');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}["toString"]["constructor"]');
|
'Expression: {}["toString"]["constructor"]');
|
||||||
|
|
||||||
scope.a = [];
|
scope.a = [];
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('a.toString.constructor', scope);
|
scope.$eval('a.toString.constructor', scope);
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: a.toString.constructor');
|
'Expression: a.toString.constructor');
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('a.toString["constructor"]', scope);
|
scope.$eval('a.toString["constructor"]', scope);
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: a.toString["constructor"]');
|
'Expression: a.toString["constructor"]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT allow access to Function constructor in setter', function() {
|
it('should NOT allow access to Function constructor in setter', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString.constructor = 1');
|
scope.$eval('{}.toString.constructor = 1');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString.constructor = 1');
|
'Expression: {}.toString.constructor = 1');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString.constructor.a = 1');
|
scope.$eval('{}.toString.constructor.a = 1');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString.constructor.a = 1');
|
'Expression: {}.toString.constructor.a = 1');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString["constructor"]["constructor"] = 1');
|
scope.$eval('{}.toString["constructor"]["constructor"] = 1');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString["constructor"]["constructor"] = 1');
|
'Expression: {}.toString["constructor"]["constructor"] = 1');
|
||||||
|
|
||||||
|
|
||||||
scope.key1 = "const";
|
scope.key1 = "const";
|
||||||
scope.key2 = "ructor";
|
scope.key2 = "ructor";
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString[key1 + key2].foo = 1');
|
scope.$eval('{}.toString[key1 + key2].foo = 1');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString[key1 + key2].foo = 1');
|
'Expression: {}.toString[key1 + key2].foo = 1');
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('{}.toString["constructor"]["a"] = 1');
|
scope.$eval('{}.toString["constructor"]["a"] = 1');
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||||
'Expression: {}.toString["constructor"]["a"] = 1');
|
'Expression: {}.toString["constructor"]["a"] = 1');
|
||||||
|
|
||||||
scope.a = [];
|
scope.a = [];
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('a.toString.constructor = 1', scope);
|
scope.$eval('a.toString.constructor = 1', scope);
|
||||||
}).toThrowMinErr(
|
}).toThrowMinErr(
|
||||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||||
'Expression: a.toString.constructor = 1');
|
'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() {
|
describe('Window and $element/node', function() {
|
||||||
scope.foo = { "bar": Function };
|
it('should NOT allow access to the Window or DOM when indexing', inject(function($window, $document) {
|
||||||
expect(function() {
|
scope.wrap = {w: $window, d: $document};
|
||||||
scope.$eval('foo["bar"]');
|
|
||||||
}).toThrowMinErr(
|
|
||||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
|
||||||
'Expression: foo["bar"]');
|
|
||||||
|
|
||||||
|
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