mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-24 03:55:49 +08:00
refactor($parse): move around previous security changes made to $parse
This commit is contained in:
@@ -1,18 +1,27 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecfld
|
||||
@fullName Referencing 'constructor' Field in Expression
|
||||
@fullName Referencing Disallowed Field in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access an objects constructor field.
|
||||
Occurs when an expression attempts to access one of the following fields:
|
||||
|
||||
AngularJS bans constructor access from within expressions since constructor
|
||||
access is a known way to execute arbitrary Javascript code.
|
||||
* __proto__
|
||||
* __defineGetter__
|
||||
* __defineSetter__
|
||||
* __lookupGetter__
|
||||
* __lookupSetter__
|
||||
|
||||
To resolve this error, avoid constructor access. As a last resort, alias
|
||||
the constructor and access it through the alias instead.
|
||||
AngularJS bans access to these fields from within expressions since
|
||||
access is a known way to mess with native objects or
|
||||
to execute arbitrary Javascript code.
|
||||
|
||||
Example expression that would result in this error:
|
||||
To resolve this error, avoid using these fields in expressions. As a last resort,
|
||||
alias their value and access them through the alias instead.
|
||||
|
||||
Example expressions that would result in this error:
|
||||
|
||||
```
|
||||
<div>{{user.constructor.name}}</div>
|
||||
```
|
||||
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
|
||||
|
||||
<div>{{user.__defineGetter__('name', noop)}}</div>
|
||||
```
|
||||
11
docs/content/error/$parse/isecobj.ngdoc
Normal file
11
docs/content/error/$parse/isecobj.ngdoc
Normal file
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecobj
|
||||
@fullName Referencing Object Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
|
||||
|
||||
Angular bans access to Object from within expressions since access is a known way to modify
|
||||
the behaviour of existing objects.
|
||||
|
||||
To resolve this error, avoid Object access.
|
||||
@@ -10,14 +10,7 @@ var $parseMinErr = minErr('$parse');
|
||||
//
|
||||
// As an example, consider the following Angular expression:
|
||||
//
|
||||
// {}.toString.constructor(alert("evil JS code"))
|
||||
//
|
||||
// We want to prevent this type of access. For the sake of performance, during the lexing phase we
|
||||
// disallow any "dotted" access to any member named "constructor".
|
||||
//
|
||||
// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
|
||||
// while evaluating the expression, which is a stronger but more expensive test. Since reflective
|
||||
// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
|
||||
// {}.toString.constructor('alert("evil JS code")')
|
||||
//
|
||||
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
|
||||
// against the expression language, but not to prevent exploits that were enabled by exposing
|
||||
@@ -25,24 +18,18 @@ var $parseMinErr = minErr('$parse');
|
||||
// practice and therefore we are not even trying to protect against interaction with an object
|
||||
// explicitly exposed in this way.
|
||||
//
|
||||
// A developer could foil the name check by aliasing the Function constructor under a different
|
||||
// name on the scope.
|
||||
//
|
||||
// In general, it is not possible to access a Window object from an angular expression unless a
|
||||
// window or some DOM object that has a reference to window is published onto a Scope.
|
||||
// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
|
||||
// native objects.
|
||||
|
||||
|
||||
function ensureSafeMemberName(name, fullExpression) {
|
||||
if (name === "constructor") {
|
||||
if (name === "__defineGetter__" || name === "__defineSetter__"
|
||||
|| name === "__lookupGetter__" || name === "__lookupSetter__"
|
||||
|| name === "__proto__") {
|
||||
throw $parseMinErr('isecfld',
|
||||
'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (name === "__defineGetter__" || name === "__defineSetter__"
|
||||
|| name === "__lookupGetter__" || name === "__lookupSetter__") {
|
||||
throw $parseMinErr('isecgetset',
|
||||
'Defining and looking up getters and setters in Angular expressions is disallowed! '
|
||||
+'Expression: {0}', fullExpression);
|
||||
} else if (name === "__proto__") {
|
||||
throw $parseMinErr('isecproto', 'Using __proto__ in Angular expressions is disallowed! '
|
||||
'Attempting to access a disallowed field in Angular expressions! '
|
||||
+'Expression: {0}', fullExpression);
|
||||
}
|
||||
return name;
|
||||
@@ -56,7 +43,7 @@ function ensureSafeObject(obj, fullExpression) {
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isWindow(obj)
|
||||
obj.document && obj.location && obj.alert && obj.setInterval) {
|
||||
obj.window === obj) {
|
||||
throw $parseMinErr('isecwindow',
|
||||
'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
@@ -65,21 +52,26 @@ function ensureSafeObject(obj, fullExpression) {
|
||||
throw $parseMinErr('isecdom',
|
||||
'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isObject(obj)
|
||||
obj.getOwnPropertyNames || obj.getOwnPropertyDescriptor) {
|
||||
} else if (// block Object so that we can't get hold of dangerous Object.* methods
|
||||
obj === Object) {
|
||||
throw $parseMinErr('isecobj',
|
||||
'Referencing Object in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (obj === ({}).__defineGetter__ || obj === ({}).__defineSetter__
|
||||
|| obj === ({}).__lookupGetter__ || obj === ({}).__lookupSetter__) {
|
||||
throw $parseMinErr('isecgetset',
|
||||
'Defining and looking up getters and setters in Angular expressions is disallowed! '
|
||||
+'Expression: {0}', fullExpression);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function ensureSafeFunction(obj, fullExpression) {
|
||||
if (obj) {
|
||||
if (obj.constructor === obj) {
|
||||
throw $parseMinErr('isecfn',
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var OPERATORS = {
|
||||
/* jshint bitwise : false */
|
||||
'null':function(){return null;},
|
||||
@@ -699,10 +691,7 @@ Parser.prototype = {
|
||||
i = indexFn(self, locals),
|
||||
v;
|
||||
|
||||
if (i === "__proto__") {
|
||||
throw $parseMinErr('isecproto', 'Using __proto__ in Angular expressions is disallowed! '
|
||||
+'Expression: {0}', parser.text);
|
||||
}
|
||||
ensureSafeMemberName(i, parser.text);
|
||||
if (!o) return undefined;
|
||||
v = ensureSafeObject(o[i], parser.text);
|
||||
return v;
|
||||
@@ -737,7 +726,7 @@ Parser.prototype = {
|
||||
var fnPtr = fn(scope, locals, context) || noop;
|
||||
|
||||
ensureSafeObject(context, parser.text);
|
||||
ensureSafeObject(fnPtr, parser.text);
|
||||
ensureSafeFunction(fnPtr, parser.text);
|
||||
|
||||
// IE stupidity! (IE doesn't have apply for some native functions)
|
||||
var v = fnPtr.apply
|
||||
@@ -832,6 +821,8 @@ function setter(obj, path, setValue, fullExp) {
|
||||
obj = propertyObj;
|
||||
}
|
||||
key = ensureSafeMemberName(element.shift(), fullExp);
|
||||
ensureSafeObject(obj, fullExp);
|
||||
ensureSafeObject(obj[key], fullExp);
|
||||
obj[key] = setValue;
|
||||
return setValue;
|
||||
}
|
||||
|
||||
@@ -638,59 +638,21 @@ describe('parser', function() {
|
||||
describe('sandboxing', function() {
|
||||
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! ' +
|
||||
'$parse', 'isecfn', 'Referencing Function 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');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString.constructor.a = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'$parse', 'isecfn','Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: {}.toString.constructor.a = 1');
|
||||
|
||||
expect(function() {
|
||||
@@ -699,14 +661,13 @@ describe('parser', function() {
|
||||
'$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');
|
||||
'Expression: {}.toString[key1 + key2].foo = 1');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.toString["constructor"]["a"] = 1');
|
||||
@@ -718,7 +679,7 @@ describe('parser', function() {
|
||||
expect(function() {
|
||||
scope.$eval('a.toString.constructor = 1', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: a.toString.constructor = 1');
|
||||
});
|
||||
|
||||
@@ -732,42 +693,24 @@ describe('parser', function() {
|
||||
'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');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Object constructor', function() {
|
||||
it('should NOT allow access to scope constructor', function() {
|
||||
expect(function() {
|
||||
scope.$eval('constructor.keys({})');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions '+
|
||||
'is disallowed! Expression: constructor.keys({})');
|
||||
});
|
||||
|
||||
it('should NOT allow access to Object constructor in getter', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}["constructor"]');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecobj', 'Referencing Object in Angular expressions is disallowed! ' +
|
||||
'Expression: {}["constructor"]');
|
||||
});
|
||||
|
||||
it('should NOT allow access to Object constructor that has been aliased', function() {
|
||||
scope.foo = { "bar": Object };
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('foo["bar"]');
|
||||
scope.$eval('foo.bar.keys(foo)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecobj', 'Referencing Object in Angular expressions is disallowed! ' +
|
||||
'Expression: foo["bar"]');
|
||||
'Expression: foo.bar.keys(foo)');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('foo["bar"]["keys"](foo)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecobj', 'Referencing Object in Angular expressions is disallowed! ' +
|
||||
'Expression: foo["bar"]["keys"](foo)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -841,126 +784,114 @@ describe('parser', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getters and setters', function() {
|
||||
it('should NOT allow invocation of __defineGetter__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineGetter__("a", "".charAt)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__defineGetter__("a", "".charAt)');
|
||||
describe('Disallowed fields', function() {
|
||||
it('should NOT allow access or invocation of __defineGetter__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineGetter__'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineGetter__("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineGetter__.call({}, "a", "".charAt)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__defineGetter__.call({}, "a", "".charAt)');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__defineGetter__"]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__defineGetter__"]("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}["__defineGetter__"].call({}, "a", "".charAt)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}["__defineGetter__"].call({}, "a", "".charAt)');
|
||||
scope.a = "__define";
|
||||
scope.b = "Getter__";
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
});
|
||||
|
||||
it('should NOT allow invocation of __defineSetter__', function() {
|
||||
it('should NOT allow access or invocation of __defineSetter__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineSetter__("a", "".charAt)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__defineSetter__("a", "".charAt)');
|
||||
scope.$eval('{}.__defineSetter__'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineSetter__("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.__defineSetter__.call({}, "a", "".charAt)');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__defineSetter__.call({}, "a", "".charAt)');
|
||||
scope.$eval('{}["__defineSetter__"]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__defineSetter__"]("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
scope.a = "__define";
|
||||
scope.b = "Setter__";
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]("a", "".charAt)'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
});
|
||||
|
||||
it('should NOT allow invocation of __lookupGetter__', function() {
|
||||
it('should NOT allow access or invocation of __lookupGetter__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupGetter__("a")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__lookupGetter__("a")');
|
||||
scope.$eval('{}.__lookupGetter__'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupGetter__("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupGetter__.call({}, "a")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__lookupGetter__.call({}, "a")');
|
||||
scope.$eval('{}["__lookupGetter__"]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__lookupGetter__"]("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
scope.a = "__lookup";
|
||||
scope.b = "Getter__";
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
});
|
||||
|
||||
it('should NOT allow invocation of __lookupSetter__', function() {
|
||||
it('should NOT allow access or invocation of __lookupSetter__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupSetter__("a")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__lookupSetter__("a")');
|
||||
scope.$eval('{}.__lookupSetter__'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupSetter__("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}.__lookupSetter__.call({}, "a")');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
|
||||
'Angular expressions is disallowed! Expression: '+
|
||||
'{}.__lookupSetter__.call({}, "a")');
|
||||
scope.$eval('{}["__lookupSetter__"]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__lookupSetter__"]("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
scope.a = "__lookup";
|
||||
scope.b = "Setter__";
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]("a")'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
});
|
||||
});
|
||||
|
||||
describe('__proto__', function() {
|
||||
it('should NOT allow access to __proto__', function() {
|
||||
expect(function() {
|
||||
scope.$eval('{}.__proto__.foo = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecproto', 'Using __proto__ in Angular expressions is disallowed!'+
|
||||
' Expression: {}.__proto__.foo = 1');
|
||||
scope.$eval('{}.__proto__'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__pro"+"to__"].foo = 1');
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecproto', 'Using __proto__ in Angular expressions is disallowed!'+
|
||||
' Expression: {}["__pro"+"to__"].foo = 1');
|
||||
scope.$eval('{}.__proto__.foo = 1'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
expect(function() {
|
||||
scope.$eval('{}["__proto__"]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}["__proto__"].foo = 1'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
|
||||
scope.a = "__pro";
|
||||
scope.b = "to__";
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b]'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
expect(function() {
|
||||
scope.$eval('{}[a + b].foo = 1'); }).toThrowMinErr('$parse', 'isecfld');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('overriding constructor', function() {
|
||||
it('should evaluate grouped expressions', function() {
|
||||
scope.foo = function foo() {
|
||||
return "foo";
|
||||
};
|
||||
// When not overridden, access should be restricted both by the dot operator and by the
|
||||
// index operator.
|
||||
it('should prevent the exploit', function() {
|
||||
expect(function() {
|
||||
scope.$eval('foo.constructor()', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: foo.constructor()');
|
||||
expect(function() {
|
||||
scope.$eval('foo["constructor"]()', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfn', 'Referencing Function in Angular expressions is disallowed! ' +
|
||||
'Expression: foo["constructor"]()');
|
||||
|
||||
// User defined value assigned to constructor.
|
||||
scope.foo.constructor = function constructor() {
|
||||
return "custom constructor";
|
||||
};
|
||||
// Dot operator should still block it.
|
||||
expect(function() {
|
||||
scope.$eval('foo.constructor()', scope);
|
||||
}).toThrowMinErr(
|
||||
'$parse', 'isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! ' +
|
||||
'Expression: foo.constructor()');
|
||||
// However, the index operator should allow it.
|
||||
expect(scope.$eval('foo["constructor"]()', scope)).toBe('custom constructor');
|
||||
});
|
||||
scope.$eval('' +
|
||||
' "".sub.call.call(' +
|
||||
'({})["constructor"].getOwnPropertyDescriptor("".sub.__proto__, "constructor").value,' +
|
||||
'null,' +
|
||||
'"alert(1)"' +
|
||||
')()' +
|
||||
'')
|
||||
}).toThrow();
|
||||
})
|
||||
});
|
||||
|
||||
it('should call the function from the received instance and not from a new one', function() {
|
||||
|
||||
Reference in New Issue
Block a user