feat: access control to prototype properties via whitelist
Disallow access to prototype properties and methods by default.
Access to properties is always checked via
`Object.prototype.hasOwnProperty.call(parent, propertyName)`.
New runtime options:
- **allowedProtoMethods**: a string-to-boolean map of property-names that are allowed if they are methods of the parent object.
- **allowedProtoProperties**: a string-to-boolean map of property-names that are allowed if they are properties but not methods of the parent object.
```js
const template = handlebars.compile('{{aString.trim}}')
const result = template({ aString: ' abc ' })
// result is empty, because trim is defined at String prototype
```
```js
const template = handlebars.compile('{{aString.trim}}')
const result = template({ aString: ' abc ' }, {
allowedProtoMethods: {
trim: true
}
})
// result = 'abc'
```
Implementation details: The method now "container.lookupProperty"
handles the prototype-checks and the white-lists. It is used in
- JavaScriptCompiler#nameLookup
- The "lookup"-helper (passed to all helpers as "options.lookupProperty")
- The "lookup" function at the container, which is used for recursive lookups in "compat" mode
Compatibility:
- **Old precompiled templates work with new runtimes**: The "options.lookupPropery"-function is passed to the helper by a wrapper, not by the compiled templated.
- **New templates work with old runtimes**: The template contains a function that is used as fallback if the "lookupProperty"-function cannot be found at the container. However, the runtime-options "allowedProtoProperties" and "allowedProtoMethods" only work with the newest runtime.
BREAKING CHANGE:
- access to prototype properties is forbidden completely by default
This commit is contained in:
committed by
Nils Knappmeier
parent
164b7ff0de
commit
d03b6ecfc4
@@ -81,4 +81,29 @@ describe('javascript-compiler api', function() {
|
||||
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidJavaScriptVariableName', function() {
|
||||
// It is there and accessible and could be used by someone. That's why we don't remove it
|
||||
// it 4.x. But if we keep it, we add a test
|
||||
// This test should not encourage you to use the function. It is not needed any more
|
||||
// and might be removed in 5.0
|
||||
['test', 'abc123', 'abc_123'].forEach(function(validVariableName) {
|
||||
it("should return true for '" + validVariableName + "'", function() {
|
||||
expect(
|
||||
handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName(
|
||||
validVariableName
|
||||
)
|
||||
).to.be.true();
|
||||
});
|
||||
});
|
||||
[('123test', 'abc()', 'abc.cde')].forEach(function(invalidVariableName) {
|
||||
it("should return true for '" + invalidVariableName + "'", function() {
|
||||
expect(
|
||||
handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName(
|
||||
invalidVariableName
|
||||
)
|
||||
).to.be.false();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user