问题
I am working with NodeJS and Express using Express-Handlebars template engine.
Handlebars is throwing the following error when trying to render a template:
Handlebars: Access has been denied to resolve the property "username" because it is not an "own property" of its parent. You can add a runtime option to disable the check or this warning: See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
According to the above link:
From version 4.6.0 on, Handlebars forbids accessing prototype properties and methods of the context object by default. The reason are various security issues that arise from this possibility.
My app.js contains the following:
const exphbs = require('express-handlebars');
const express = require('express');
// Init Express
const app = express();
// VIEW ENGINE
app.engine('handlebars', exphbs({
defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');
My route file fetches from MongoDB via Mongoose:
//@GET - View
router.get('/', authMiddleware, (req, res, next) => {
// Mongoose
Model.find({ user: req.user._id })
.sort({ date: -1 })
.then(model => {
res.render('/overview', { model: model })
})
.catch(err => {
if (err) throw err;
req.flash('error_msg', 'No Model Found');
})
})
model is an array of objects
This issue only started happening after I began to mess around with adding handlebar helpers. I have removed the helpers and reverted to my original configuration settings (above) to no avail. I've tried deleting node_modules folder and reinstalling npm.
What's being sent is an array of objects, and I am trying to loop over the properties of the objects using the {{#each model}} helper and reference the individual properties via {{prop1}} within the each.
According to Handlebars, this disabling of proto properties is false by default, and this change shouldn't break anything.
My question:
- Am I sending data to handlebars incorrectly? If so, what is the correct method (not exposing my server to security holes) to send data to the express-handlebars template for rendering?
Thank you in advance.
回答1:
Correct! I used to work with Sequelize
and toJSON()
did the trick.
If you tried it already and it didn't work, I think the same result in Mongoose could be achieved by using lean – mas 2 hours ago
I added .lean
between .sort()
and .then()
, This worked!
回答2:
I had the same issue when I upgraded the handlebars package. To get your system back online as quick as possible remove the handlebars entry in package.json And then insert this line in its place.
"handlebars": "4.5.3",
From version 4.6.0 onward Handlebars forbids accessing prototype properties and methods of the context object by default. This is related to a security issue described here: https://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html
Refer to https://github.com/wycats/handlebars.js/issues/1642
An example from the above URL shows the Mongoose response converted into JSON:
app.get('/test', function (_req, res) {
Kitten.find({}).then(kittens => {
res.render('test.hbs', {
kittens: kittens.map(kitten => kitten.toJSON())
})
})
});
If you are certain that only trusted developers and no end users have access to the handlebars templates it's possible to allow prototype access by installing the following package:
npm install @handlebars/allow-prototype-access
Here is an example of it's use:
const express = require('express');
const Handlebars = require('handlebars')
const expressHandlebars = require('express-handlebars');
const {allowInsecurePrototypeAccess} = require('@handlebars/allow-prototype-access')
const app = express();
app.engine('handlebars', expressHandlebars({
handlebars: allowInsecurePrototypeAccess(Handlebars)
}));
app.set('view engine', 'handlebars');
...
Another option is to use the mongoose .lean() function. This has the benefit of being much faster than a traditional mongoose query. But it does have some cons as well. By default, Mongoose queries return an instance of the Mongoose Document class. These objects contain a lot of internal state for change tracking and have additional methods such as .save(). Enabling the lean option tells Mongoose to skip instantiating a full Mongoose document and just return the plain javascript object.
回答3:
As answered @OctavianLabs it's helped for me:
const posts = await this.find({})
.limit(amount)
.lean();
The lean
method of mongoose returns plain JavaScript objects (POJOs), not Mongoose documents.
回答4:
@OctavianLabs for that kind of error.you should try following code.
Model.find({ user: req.user._id })
.sort({ date: -1 })
.lean()
.then(model => {
res.render('/overview', { model: model })
})
回答5:
use .lean()
after .find()
it works properly
来源:https://stackoverflow.com/questions/59753149/express-handlebars-wont-render-data