车把:拒绝访问以解析“来源”属性,因为它不是其父项的“拥有财产”


15

我正在使用带有手柄的服务器端渲染的Nodejs后端。doc从车把读取一组对象后,其中包含键“ content”和“ from”。但是,当我尝试用于#each遍历对象数组时,会出现错误“ Handlebars:访问已被拒绝以解析属性”来自”,因为它不是其父级的“拥有属性”。

我试图将我在doc数组中获取的数据进行console.log(),一切似乎都很好。


从某种角度来说,这是猫鼬查询,我已将对象doc作为键添加到res.render参数中。

Confession.find()
  .sort({date: -1})
  .then(function(doc){
    for(var i=0; i < doc.length; i++){
      //Check whether sender is anonymous
      if (doc[i].from === "" || doc[i].from == null){
        doc[i].from = "Anonymous";
      }

      //Add an extra JSON Field for formatted date
      doc[i].formattedDate = formatTime(doc[i].date);
    }
    res.render('index', {title: 'Confession Box', success:req.session.success, errors: req.session.errors, confession: doc});
    req.session.errors = null;
    req.session.success = null;
  });

这是我要遍历的.hbs文件的一部分:

 {{#each confession}}
    <div class="uk-card uk-card-default uk-card-body uk-margin uk-align-center uk-width-1-2@m" >
        <div class="uk-text-bold">Message: </div>
        <div>{{this.content}}</div>
        <div>From: {{this.from}}</div>
        <div>Posted: {{this.formattedDate}}</div>
    </div>
    {{/each}}

Answers:


25

我通过为车把安装开发依赖项来解决此问题

npm i -D handlebars@4.5.0


哇,这行得通,为什么会这样呢?我目前正在使用express-handlebars(3.1.0),在我的express应用程序中将其设置为渲染引擎。
李文刚

由于某些限制,我怀疑这是在较新版本的车把上发生的,但我不知道如何处理这些限制。
李文刚

嗯,问题出在支持车把的Express插件之间,但是一旦把车把4.5.0保存为前端的主要引擎,请通过评论告知我。
梅森

这是行不通的。在执行npm i -D handlebars@4.5.0
Deepak Thakur


12

如果使用猫鼬,可以通过使用.lean()来获取json对象(而不是猫鼬)来解决此问题:

dbName.find({}).lean()
  // execute query
  .exec(function(error, body) {
     //Some code
  });

3
上帝祝福你!节省生命!
Nick Thenick

1
没问题,很高兴它有所帮助!
Billeh

2
希望我能多次赞成这个答案..哈哈非常感谢!
Abdus

7

今天,我从车把收到同样的警告,并且视图为空。以下是我如何解决的问题:

//  * USERS PAGE
// @description        users route
// @returns           ../views/users.hbs
router.get('/users', async (req, res) => {
  // get all items from db collection
  const collection = 'User'
  await dbFindAllDocs(collection) // <=> wrapper for Model.find() ...
    .then(documents => {
      // create context Object with 'usersDocuments' key
      const context = {
        usersDocuments: documents.map(document => {
          return {
            name: document.name,
            location: document.location
          }
        })
      }
      // rendering usersDocuments from context Object
      res.render('users', {
        usersDocuments: context.usersDocuments
      })
    })
    .catch(error => res.status(500).send(error))
})

users.hbs文件

<ul>
{{#each usersDocuments}}
<li>name: {{this.name}} location: {{this.location}}</li>
{{/each}}    
</ul>

创建一个完整的名为 context具有自己属性的,然后将其传递给render函数将解决此问题。

注意:

当我们不创建新对象时,很容易意外泄露机密信息或可能损害项目安全性的信息,映射从数据库返回的数据并将仅需要的信息传递给视图可能是一个好习惯...


非常感谢您的回答!似乎最好创建一个新对象以防止不必要的数据泄露。
李文刚

感谢这项工作。
GNETO DOMINIQUE

通过从已准备好的列表中准备新列表来渲染是否要花费2倍的时间?
mustafiz012

6

“哇,这行得通,为什么会这样呢?我目前正在使用Express-Handlebars(3.1.0),在我的express应用程序中将其设置为渲染引擎。” –李文刚1月12日14:13

“过去,Handlebars允许您从模板访问输入对象的原型方法和属性...这种行为产生了多个安全问题...在handlebars@^4.6.0中,可以访问对象原型。现在,如果您将自定义类用作Handlebars的输入,则您的代码将无法再使用...该软件包会自动将运行时选项添加到每个模板调用中,从而禁用安全限制... 如果您的用户正在编写模板,并且在服务器上执行它们,则不应使用此程序包,而应寻找其他方法来解决问题...我建议您先将类实例转换为普通的JavaScript对象,然后再将其传递给模板函数。您访问的每个属性或功能都必须是其父级的“自有属性”。” –自述文件

此处有更多详细信息:https : //www.npmjs.com/package/@handlebars/allow-prototype-access

快速和肮脏的保险方法

用法(express-handlebarsmongoose):

express-handlebars不允许您指定运行时选项以传递给模板函数。该软件包可以帮助您禁用模型的原型检查。

“如果您完全控制服务器中执行的模板,则只能这样做。”

脚步:

1-安装依赖性

npm i @handlebars/allow-prototype-access

2-使用此代码段作为示例来重写您的快速服务器

const express = require('express');
const mongoose = require('mongoose');
const Handlebars = require('handlebars');
const exphbs = require('express-handlebars');

// Import function exported by newly installed node modules.
const { allowInsecurePrototypeAccess } = require('@handlebars/allow-prototype->access');

const PORT = process.env.PORT || 3000;

const app = express();

const routes = require('./routes');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static('public'));

// When connecting Handlebars to the Express app...
app.engine('handlebars', exphbs({
    defaultLayout: 'main',
    // ...implement newly added insecure prototype access
    handlebars: allowInsecurePrototypeAccess(Handlebars)
    })
);
app.set('view engine', 'handlebars');

app.use(routes);

const MONGODB_URI = process.env.MONGODB_URI || >'mongodb://localhost/dbName';

mongoose.connect(MONGODB_URI);

app.listen(PORT, function () {
  console.log('Listening on port: ' + PORT);
});

3-运行服务器,然后跳舞。


更安全的方法

在将AJAX调用返回的对象传递到Handlebars模板之前,请将其映射到具有您需要在.hbs文件中访问的每个属性或函数的新对象。在下面,您可以看到在将新对象传递到Handlebars模板之前制作的新对象。

const router = require("express").Router();
const db = require("../../models");

router.get("/", function (req, res) {
    db.Article.find({ saved: false })
        .sort({ date: -1 })
        .then(oldArticleObject => {
            const newArticleObject = {
                articles: oldArticleObject.map(data => {
                    return {
                        headline: data.headline,
                        summary: data.summary,
                        url: data.url,
                        date: data.date,
                        saved: data.saved
                    }
                })
            }
            res.render("home", {
                articles: newArticleObject.articles
            })
        })
        .catch(error => res.status(500).send(error));
});

您的猫鼬查询

如果我错了,请纠正我,但我认为这可能对您的查询有用...

Confession.find()
    .sort({ date: -1 })
    .then(function (oldDoc) {

        for (var i = 0; i < oldDoc.length; i++) {
            //Check whether sender is anonymous
            if (oldDoc[i].from === "" || oldDoc[i].from == null) {
                oldDoc[i].from = "Anonymous";
            }

            //Add an extra JSON Field for formatted date
            oldDoc[i].formattedDate = formatTime(oldDoc[i].date);
        }

        const newDoc = {
            doc: oldDoc.map(function (data) {
                return {
                    from: data.from,
                    formattedDate: data.formattedDate
                }
            })
        }

        res.render('index', { title: 'Confession Box', success: req.session.success, errors: req.session.errors, confession: newDoc.doc });
        req.session.errors = null;
        req.session.success = null;
    });

5

尝试npm install handlebars版本4.5.3

npm install handlebars@4.5.3

对我有用


这应该是一条评论
Arun Vinoth

我目前正在使用3.1.0版的快速车把
Lee Boon Kong

谢谢,我已经尝试过您的,并且@Mason的anwser都可以使用,但是我不确定为什么会这样。
李文刚

3

从版本4.6.0开始,默认情况下,Handlebars禁止访问原型属性和上下文对象的方法。这与此处描述的安全问题有关:https : //mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html

请参阅https://github.com/wycats/handlebars.js/issues/1642

如果您确定只有开发人员可以访问模板,则可以通过安装以下软件包来允许原型访问:

npm i @handlebars/allow-prototype-access

如果使用快速车把,则应按以下步骤操作:

const 
    express = require('express'),
    _handlebars = require('handlebars'),
    expressHandlebars = require('express-handlebars'),
    {allowInsecurePrototypeAccess} = require('@handlebars/allow-prototype-access')

const app = express()

app.engine('handlebars', expressHandlebars({
    handlebars: allowInsecurePrototypeAccess(_handlebars)
}))
app.set('view engine', 'handlebars')

谢谢你的工作。因此,每次必须使用快速车把时都要这样做吗?
Yash Boura

2

最近发布的Handlebars中发生重大更改,导致了此错误。

您可以简单地在他们的文档中添加他们建议的配置,但是请注意,根据您的实现,这可能导致漏洞受到XXS和RCE攻击。

https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access

Confession.find()
  .sort({date: -1})
  .then(function(doc){
    for(var i=0; i < doc.length; i++){
      //Check whether sender is anonymous
      if (doc[i].from === "" || doc[i].from == null){
        doc[i].from = "Anonymous";
      }

      //Add an extra JSON Field for formatted date
      doc[i].formattedDate = formatTime(doc[i].date);
    }
    res.render('index', {title: 'Confession Box', success:req.session.success, errors: req.session.errors, confession: doc}, {

      // Options to allow access to the properties and methods which as causing the error.

      allowProtoMethodsByDefault: true,
      allowProtoPropertiesByDefault: true

    });

    req.session.errors = null;
    req.session.success = null;
  });

啊,那是我添加选项的地方,非常感谢!
李文刚

1
这对我不起作用。期望回调,而不是选项对象。
mrg95

0

根据返回的数据创建另一个新的Object或Array find() 将解决此问题。参见下面的简单图示

app.get("/",(req,res)=>{

 let com = require('./MODELCOM')    // loading model
 let source=fs.readFileSync(__dirname+"/views/template.hbs","utf-8");

 com.find((err,data)=>{
    // creation new array  using map
   let wanted = data.map(doc=>{
       return {
           name:doc.name,
           _id:doc._id
        }
   })

    let html= handlebar.compile(source);
  fs.writeFileSync(__dirname+"/views/reciever.html",html({communities:wanted}))
    res.sendFile(__dirname+"/views/reciever.html")
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.